package com.tbl.modules.wms.service.Impl.pda;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.tbl.common.config.ConRunningMap;
import com.tbl.common.utils.DateUtils;
import com.tbl.common.utils.StringUtils;
import com.tbl.modules.platform.dao.system.UserDAO;
import com.tbl.modules.platform.entity.system.User;
import com.tbl.modules.wms.constant.Constant;
import com.tbl.modules.wms.constant.EbsInterfaceEnum;
import com.tbl.modules.wms.constant.EmumConstant;
import com.tbl.modules.wms.constant.PdaResult;
import com.tbl.modules.wms.dao.allo.AlloInStorageDAO;
import com.tbl.modules.wms.dao.allo.AlloOutStorageDAO;
import com.tbl.modules.wms.dao.allo.AllocationDAO;
import com.tbl.modules.wms.dao.allo.AllocationDetailDAO;
import com.tbl.modules.wms.dao.baseinfo.*;
import com.tbl.modules.wms.dao.instorage.InstorageDAO;
import com.tbl.modules.wms.dao.instorage.InstorageDetailDAO;
import com.tbl.modules.wms.dao.inventory.InventoryDAO;
import com.tbl.modules.wms.dao.inventory.InventoryInDAO;
import com.tbl.modules.wms.dao.inventory.InventoryRegistrationDAO;
import com.tbl.modules.wms.dao.move.MoveInStorageDAO;
import com.tbl.modules.wms.dao.move.MoveOutStorageDAO;
import com.tbl.modules.wms.dao.move.MoveStorageDAO;
import com.tbl.modules.wms.dao.move.MoveStorageDetailDAO;
import com.tbl.modules.wms.dao.outstorage.ExchangePrintDAO;
import com.tbl.modules.wms.dao.outstorage.OutStorageDetailDAO;
import com.tbl.modules.wms.dao.outstorage.OutstorageDAO;
import com.tbl.modules.wms.dao.outstorage.ShipLoadingDetailDAO;
import com.tbl.modules.wms.dao.pda.PdaDAO;
import com.tbl.modules.wms.dao.pda.RfidBindDAO;
import com.tbl.modules.wms.dao.pda.SplitDAO;
import com.tbl.modules.wms.dao.pda.SplitInstorageDAO;
import com.tbl.modules.wms.dao.productbind.DeviceUwbRouteDAO;
import com.tbl.modules.wms.dao.storageinfo.StorageInfoDAO;
import com.tbl.modules.wms.dao.webservice.FewmDAO;
import com.tbl.modules.wms.entity.allo.AlloInStorage;
import com.tbl.modules.wms.entity.allo.AlloOutStorage;
import com.tbl.modules.wms.entity.allo.Allocation;
import com.tbl.modules.wms.entity.allo.AllocationDetail;
import com.tbl.modules.wms.entity.baseinfo.*;
import com.tbl.modules.wms.entity.instorage.Instorage;
import com.tbl.modules.wms.entity.instorage.InstorageDetail;
import com.tbl.modules.wms.entity.inventory.Inventory;
import com.tbl.modules.wms.entity.inventory.InventoryIn;
import com.tbl.modules.wms.entity.inventory.InventoryRegistration;
import com.tbl.modules.wms.entity.move.MoveInStorage;
import com.tbl.modules.wms.entity.move.MoveOutStorage;
import com.tbl.modules.wms.entity.move.MoveStorageDetail;
import com.tbl.modules.wms.entity.outstorage.OutStorage;
import com.tbl.modules.wms.entity.outstorage.OutStorageDetail;
import com.tbl.modules.wms.entity.outstorage.ShipLoadingDetail;
import com.tbl.modules.wms.entity.productbind.DeviceUwbRoute;
import com.tbl.modules.wms.entity.split.RfidBind;
import com.tbl.modules.wms.entity.split.Split;
import com.tbl.modules.wms.entity.storageinfo.StorageInfo;
import com.tbl.modules.wms.service.Impl.baseinfo.ShelfServiceImpl;
import com.tbl.modules.wms.service.Impl.interfaceLog.InterfaceDoServiceImpl;
import com.tbl.modules.wms.service.Impl.outstorage.ExchangePrintDetailServiceImpl;
import com.tbl.modules.wms.service.Impl.outstorage.ExchangePrintServiceImpl;
import com.tbl.modules.wms.service.pda.PdaService;
import net.sf.json.JSONArray;
import org.apache.poi.ss.formula.functions.T;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpSession;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 手持机接口实现
 * @author 70486
 */
@Service
public class PdaServiceImpl extends ServiceImpl<PdaDAO, T> implements PdaService {

    /**
     * 日志信息
     */
    private final Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * 手持机
     */
    @Autowired
    private PdaDAO pdaDAO;
    /**
     * 库存
     */
    @Autowired
    private StorageInfoDAO storageInfoDAO;
    /**
     * 仓库
     */
    @Autowired
    private WarehouseDAO warehouseDAO;
    /**
     * 行车
     */
    @Autowired
    private CarDAO carDAO;
    /**
     * 调拨管理
     */
    @Autowired
    private AllocationDAO allocationDAO;
    /**
     * 调拨管理明细
     */
    @Autowired
    private AllocationDetailDAO allocationDetailDAO;
    /**
     * 调拨入库
     */
    @Autowired
    private AlloInStorageDAO alloInStorageDAO;
    /**
     * 调拨出库
     */
    @Autowired
    private AlloOutStorageDAO alloOutStorageDAO;
    /**
     * 移库处理
     */
    @Autowired
    private MoveStorageDAO moveStorageDAO;
    /**
     * 移库处理-详情
     */
    @Autowired
    private MoveStorageDetailDAO moveStorageDetailDAO;
    /**
     * 移库入库
     */
    @Autowired
    private MoveInStorageDAO moveInStorageDAO;
    /**
     * 移库出库
     */
    @Autowired
    private MoveOutStorageDAO moveOutStorageDAO;
    /**
     * 盘点登记
     */
    @Autowired
    private InventoryRegistrationDAO inventoryRegistrationDAO;
    /**
     * 入库详情
     */
    @Autowired
    private InstorageDetailDAO instorageDetailDAO;
    /**
     * 入库管理
     */
    @Autowired
    private InstorageDAO instorageDAO;
    /**
     * 出库详情
     */
    @Autowired
    private OutStorageDetailDAO outStorageDetailDAO;
    /**
     * 用户
     */
    @Autowired
    private UserDAO userDAO;
    /**
     * 拆分
     */
    @Autowired
    private SplitDAO splitDAO;
    /**
     * 拆分入库
     */
    @Autowired
    private SplitInstorageDAO splitInstorageDAO;
    /**
     * RFID绑定
     */
    @Autowired
    private RfidBindDAO rfidBindDAO;
    /**
     * 出库信息
     */
    @Autowired
    private OutstorageDAO outstorageDAO;
    /**
     * 盘具
     */
    @Autowired
    private DishDAO dishDAO;
    /**
     * 库位信息
     */
    @Autowired
    private ShelfDAO shelfDAO;
    /**
     * 厂区
     */
    @Autowired
    private FactoryAreaDAO factoryAreaDAO;
    /**
     * 库位
     */
    @Autowired
    private ShelfServiceImpl shelfImpl;
    /**
     * 接口执行
     */
    @Autowired
    private InterfaceDoServiceImpl interfaceDoServiceImpl;
    /**
     * 行车坐标
     */
    @Autowired
    private DeviceUwbRouteDAO deviceUwbRouteDAO;
    /**
     * Webservice服务的接口方法DAO
     */
    @Autowired
    private FewmDAO fewmDAO;
    /**
     * 真实库位获取坐标记录
     */
    @Autowired
    private RealLocationDAO realLocationDAO;
    /**
     * 记录推荐库位
     */
    @Autowired
    private ShipLoadingDetailDAO shipLoadingDetailDAO;
    /**
     * 移库设置库位占用状态开关
     */
    @Value("${yddl.moveSoluation}")
    private String moveSoluation;
    /**
     * 盘点扫码日志
     */
    @Autowired
    private ExternalcableDAO externalcableDAO;
    /**
     * 盘点主表
     */
    @Autowired
    private InventoryDAO inventoryDAO;
    /**
     * 入库生成盘号日志记录
     */
    @Autowired
    private InventoryInDAO inventoryInDAO;
    /**
     * 物资流转单明细
     */
    @Autowired
    private ExchangePrintDetailServiceImpl exchangePrintDetailServiceImpl;
    /**
     * 物资流转单
     */
    @Autowired
    private ExchangePrintDAO exchangePrintDAO;
    @Autowired
    private ExchangePrintServiceImpl exchangePrintServiceImpl;

    /**
     * 用户登陆
     * @param username 用户名
     * @param password 密码
     * @param session
     * @return PdaResult
     */
    @Override
    public PdaResult login(String username, String password, HttpSession session) {
        // 密码加密
        String passwd = new SimpleHash("SHA-1", password, username).toString();
        List<User> lstUser = userDAO.selectByMap(new HashMap<String, Object>() {{
            put("USERNAME", username);
            put("PASSWORD", passwd);
        }});

        if (lstUser == null || lstUser.size() != 1) {
            return new PdaResult(1, "用户名密码输入错误或用户名不存在！", "");
        }

//        session.setAttribute("username",username);
//        session.setAttribute("password",password);
        session.setAttribute("sessionUser",lstUser.get(0));

        return new PdaResult(new HashMap<String, Object>(2) {{
            put("userId", lstUser.get(0).getUserId());
            put("menuList", pdaDAO.getMenuList(lstUser.get(0).getRoleId(), 2));
        }});
    }

    /**
     * 台账扫描:获取物料详情列表
     * @param rfid rfid
     * @param userId 用户
     * @param barcode 二维码信息
     * @param barcodeType 二维码类型
     * @param dictTypeNum 台账类型
     * @return PdaResult 状态为未包装的详情列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageinPackingDetailList(String rfid, Long userId, String barcode, String barcodeType, String dictTypeNum) {
        if(StringUtils.isBlank(dictTypeNum)){
            return new PdaResult(1, "请选择台账类型！", "");
        }
        Map<String,Object> map = new HashMap<>(4);
        map.put("barcode", barcode);
        map.put("barcodeType", barcodeType);
        map.put("rfid", rfid);
        map.put("org", Arrays.asList(userDAO.selectById(userId).getFactoryCode().split(",")));
        List<InstorageDetail> lstInstorageDetail = instorageDetailDAO.selectList(map);
        String msg = "";
        int type = 1;
        if(lstInstorageDetail==null||lstInstorageDetail.size()!=1){
            msg = "系统中不存在此货物信息，请联系管理员查看";
        }else {
            InstorageDetail instorageDetail = lstInstorageDetail.get(0);
            switch (dictTypeNum){
                case "1":
                    if(instorageDetail.getConfirmBy()!=null){
                        msg = "已经进行过包装扫描，无需再次扫描";
                    }else {
                        type = 0;
                    }
                    break;

                case "2":
                    if(instorageDetail.getHoistingid()!=null){
                        msg = "已经进行过吊装扫描，无需再次扫描";
                    }else {
                        type = 0;
                    }
                    break;

                case "3":
                    if(instorageDetail.getRewindingid()!=null){
                        msg = "已经进行过复绕扫描，无需再次扫描";
                    }else {
                        type = 0;
                    }
                    break;
                default: type = 0;
            }

            instorageDetail.setScantime(new Date());
            instorageDetailDAO.updateById(instorageDetail);
        }

        return new PdaResult(type, msg, lstInstorageDetail);
    }

    /**
     * 台账:点击确认
     * @param queryMap rfid
     * @return PdaResult 详情表列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageinPackingSubmit(Map<String, Object> queryMap) {
        @SuppressWarnings("unchecked")
        List<InstorageDetail> lstInstorageDetail = pdaDAO.getPackingList((List<String>)queryMap.get("data"));
        //台账类型
        String dictTypeNum = (String) queryMap.get("DICT_TYPE_NUM");
        if(StringUtils.isBlank(dictTypeNum)){
            return new PdaResult(1, "请选择台账类型！", "");
        }
        lstInstorageDetail.forEach(instorageDetail -> {
            instorageDetail.setDictTypeNum(dictTypeNum);
            //包装
            switch (dictTypeNum) {
                case "1":
                    if ((instorageDetail.getState() == 1 || instorageDetail.getState() == 5)) {
                        instorageDetail.setState(2);
                    }
                    instorageDetail.setConfirmBy(Long.valueOf((String) queryMap.get("userId")));
                    break;
                case "2":
                    //吊装
                    instorageDetail.setHoistState(1);
                    instorageDetail.setHoistingid(Long.valueOf((String) queryMap.get("userId")));
                    break;
                case "3":
                    //复绕
                    instorageDetail.setRewindState(1);
                    instorageDetail.setRewindingid(Long.valueOf((String) queryMap.get("userId")));
                    break;
            }
        });

        pdaDAO.storageinPackingSubmit(lstInstorageDetail);
        return new PdaResult();
    }

    /**
     * 入库:返回仓库列表
     * @param pageNo 页码
     * @param size 每页数量
     * @param factoryCode 厂区编码
     * @param code 查询条件
     * @return PdaResult 仓库列表
     */
    @Override
    public PdaResult storageinStorageinStart(String pageNo, String size, String factoryCode, String code) {
        return new PdaResult(pdaDAO.storageinStorageinStart(new Page(1,1000), factoryCode, code));
    }

    /**
     * 入库:选择行车
     * @param warehouseCode 仓库编码
     * @param factoryCode 厂区编码
     * @return PdaResult 行车列表
     */
    @Override
    public PdaResult storageinStorageinCar(String warehouseCode,String factoryCode) {
        return new PdaResult(carDAO.selectList(new EntityWrapper<Car>()
                .eq("WAREHOUSECODE",warehouseCode)
                .eq("FACTORYCODE",factoryCode)));
    }

    /**
     * 入库:扫描
     * @param warehouseCode 仓库编码
     * @param rfid rfid
     * @param factoryCode 厂区编码
     * @param barcode 二维码
     * @param barcodeType 二维码类型
     * @param carCode 行车编码
     * @param isCertificate 是否是合格证扫描：0不是。1是
     * @param userId 用户
     * @return PdaResult 推荐库位，物料详情
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageinStorageinScan(String warehouseCode,String rfid,String factoryCode,String barcode,String barcodeType,
                                            String carCode,String isCertificate, Long userId) {
        //false：不是合格证扫描；true：是合格证扫描
    	boolean isCertificateFlag = "1".equals(isCertificate);

    	Car car = null;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(carCode)){
            car = carDAO.selectOne(new Car() {{
                setCode(carCode);
            }});
        }

        Map<String, Object> map = Maps.newHashMap();
        map.put("barcode", barcode);
        map.put("barcodeType", barcodeType);
        map.put("rfid", rfid);
        InstorageDetail instorageDetail = pdaDAO.findInstorageDetailByqbr(map);

        if (instorageDetail == null) {
        	return new PdaResult(1, "该货物信息不存在，请联系管理员查看!", "");
        }else {
        	Integer state = instorageDetail.getState();
        	if(state==4 && !isCertificateFlag) {
        	    return new PdaResult(1, "该货物已入库，请勿重复入库!", "");
            }
        	/*//未包装扫描的货物，默认进行包装扫描
        	if(state==1 && !isCertificateFlag) {
        	    instorageDetail.setState(Constant.INT_TWO);
        	    instorageDetail.setConfirmBy(userId);
        	    instorageDetail.setConfirmTime(new Date());
            }*/

            instorageDetail.setCarCode(carCode);
            //入库扫描时间
            instorageDetail.setStartStorageTime(new Date());
            //入库扫描人
            instorageDetail.setStartstorageid(userId);
            instorageDetail.setState(EmumConstant.instorageDetailState.STORAGEING.getCode());
            instorageDetailDAO.updateById(instorageDetail);

            //获取推荐库位
            List<Shelf> recommendList = shelfImpl.selectRecommentList(factoryCode,warehouseCode,instorageDetail.getOuterDiameter()!=null?
                    instorageDetail.getOuterDiameter().toString() : "", instorageDetail.getDrumType(), carCode,"", car != null ?
                    car.getWarehouseArea() : "", instorageDetail.getSalesCode(), instorageDetail.getSuperWide(),
                    "黑色".equals(instorageDetail.getColour()) || StringUtils.isBlank(instorageDetail.getColour()) ? 0 : 1);
            //按规则查找没有可以推荐的库位，那么就任意取一个可用的库位
            if(recommendList==null||recommendList.size()==0) {
                recommendList = new ArrayList<>();
                List<Shelf> useShelfList = shelfDAO.getRecommendShelf(warehouseCode, factoryCode, car != null &&
                        StringUtils.isNotBlank(car.getWarehouseArea()) ? Arrays.asList(car.getWarehouseArea().split(",")) :
                        new ArrayList<>());
                if(useShelfList!=null&&useShelfList.size()>0) {
                    recommendList.add(useShelfList.get(0));
                }
            }

        	//推荐库位任务推给航车
            if (car!=null){
                car.setMission(recommendList.size() > 0 ? recommendList.get(0).getCode() : "");
                carDAO.updateById(car);
            }

            //记录推荐库位
            ShipLoadingDetail shipLoadingDetail = new ShipLoadingDetail();
            shipLoadingDetail.setCreateTime(new Date());
            shipLoadingDetail.setMaterialCode(recommendList.size() > 0 ? recommendList.get(0).getCode() : "");
            shipLoadingDetail.setQaCode(instorageDetail.getQaCode());
            shipLoadingDetail.setPId(userId);
            shipLoadingDetail.setShipNo("入库");
            shipLoadingDetailDAO.insert(shipLoadingDetail);

        	Map<String,Object> resultMap = new HashMap<>(2);
            resultMap.put("shelfList", recommendList);
            instorageDetail.setFactoryCode(factoryCode);
            instorageDetail.setWarehouseCode(warehouseCode);
            resultMap.put("detail", instorageDetail);
        	return new PdaResult(resultMap);
        }
    }
    
    /**
     * 入库:再次扫描（操作员发现入错了，应该时入另一盘）
     * @param warehouseCode 新仓库编码
     * @param rfid 新rfid
     * @param factoryCode 新厂区编码
     * @param originalRfid 原rfid
     * @param barcode 二维码
     * @param barcodeType 扫描类型
     * @param carCode 行车
     * @param isCertificate 是否是合格证扫描：0不是。1是
     * @param userId 操作员
     * @return PdaResult 推荐库位，物料详情
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult againStorageinScan(String warehouseCode, String rfid, String factoryCode, String originalRfid, String barcode,
                                        String barcodeType, String carCode, String isCertificate, Long userId) {
        //false:不是合格证扫描；true：是合格证扫描
    	boolean isCertificateFlag = "1".equals(isCertificate);

        Car car = null;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(carCode)){
            car = carDAO.selectOne(new Car() {{
                setCode(carCode);
            }});
        }

        Map<String, Object> map = Maps.newHashMap();
        map.put("barcode", barcode);
        map.put("barcodeType", barcodeType);
        map.put("rfid", rfid);
        InstorageDetail instorageDetail = pdaDAO.findInstorageDetailByqbr(map);

        if (instorageDetail == null) {
        	return new PdaResult(1, "这条货物数据不存在!", "");
        }else {
        	Integer state = instorageDetail.getState();
        	if(EmumConstant.instorageDetailState.STORAGED.getCode().equals(state) && !isCertificateFlag) {
        	    return new PdaResult(1, "该货物已入库，请勿重复入库!", "");
            }
            /*//未包装扫描的货物，默认进行包装扫描
            if(state==1&&!isCertificateFlag) {
                instorageDetail.setState(Constant.INT_TWO);
                instorageDetail.setConfirmBy(userId);
                instorageDetail.setConfirmTime(new Date());
            }*/

            instorageDetail.setCarCode(carCode);
            instorageDetail.setStartStorageTime(new Date());
            instorageDetail.setState(EmumConstant.instorageDetailState.STORAGEING.getCode());
            instorageDetailDAO.updateById(instorageDetail);

            List<Shelf> recommendList = shelfImpl.selectRecommentList(factoryCode,warehouseCode,instorageDetail.getOuterDiameter()!=null?
                    instorageDetail.getOuterDiameter().toString():"", instorageDetail.getDrumType(), carCode, "", car!= null ?
                    car.getWarehouseArea() : "", instorageDetail.getSalesCode(), instorageDetail.getSuperWide(),
                    "黑色".equals(instorageDetail.getColour()) || StringUtils.isBlank(instorageDetail.getColour()) ? 0 : 1);
            if (recommendList==null||recommendList.size() == 0) {
                recommendList = new ArrayList<>();
                List<Shelf> useShelfList = shelfDAO.getRecommendShelf(warehouseCode, factoryCode, car != null &&
                        StringUtils.isNotBlank(car.getWarehouseArea()) ?
                        Arrays.asList(car.getWarehouseArea().split(",")) : new ArrayList<>());
                if (useShelfList.size() > 0) {
                    recommendList.add(useShelfList.get(0));
                }
            }

        	//将上一盘货物状态置为“已包装”
            if (!instorageDetail.getRfid().equals(originalRfid)){
                InstorageDetail originalDetail = instorageDetailDAO.selectOne(new InstorageDetail() {{
                    setRfid(originalRfid);
                }});
                originalDetail.setState(EmumConstant.instorageDetailState.PACKAGED.getCode());
                instorageDetailDAO.updateById(originalDetail);

                //将上一盘货物所选的航车状态置空,任务清空
                carDAO.updateCarByCode(originalDetail.getCarCode(),"",Long.valueOf(EmumConstant.carState.UNUSED.getCode()));
            }

            //推荐库位任务推给航车
            if (car!=null){
                car.setMission(recommendList.size() > 0 ? recommendList.get(0).getCode() : "");
                carDAO.updateById(car);
            }

            //记录推荐库位
            ShipLoadingDetail shipLoadingDetail = new ShipLoadingDetail();
            shipLoadingDetail.setCreateTime(new Date());
            shipLoadingDetail.setMaterialCode(recommendList.size() > 0 ? recommendList.get(0).getCode() : "");
            shipLoadingDetail.setQaCode(instorageDetail.getQaCode());
            shipLoadingDetail.setPId(userId);
            shipLoadingDetail.setShipNo("入库");
            shipLoadingDetailDAO.insert(shipLoadingDetail);

            Map<String, Object> resultMap = new HashMap<>(2);
            resultMap.put("shelfList",recommendList);
            instorageDetail.setFactoryCode(factoryCode);
            instorageDetail.setWarehouseCode(warehouseCode);
            resultMap.put("detail",instorageDetail);
        	return new PdaResult(resultMap);
        }
    }

    /**
     * 开始入库:选择推荐库位后提交
     * @param rfid rfid
     * @param shelfCode 库位编码
     * @param warehouseCode 仓库编码
     * @param carCode 行车编码
     * @param factoryCode 厂区编码
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageinStorageinSubmit(String rfid, String shelfCode, String warehouseCode, String carCode, String factoryCode) {
        List<InstorageDetail> lstInstorageDetail = instorageDetailDAO.selectByMap(new HashMap<String, Object>(1) {{
            put("RFID", rfid);
        }});

        InstorageDetail instorageDetail = lstInstorageDetail.get(0);
        instorageDetail.setWarehouseCode(warehouseCode);
        instorageDetail.setCarCode(carCode);
        instorageDetail.setShelfCode(shelfCode);
        instorageDetail.setStartStorageTime(new Date());
        instorageDetail.setState(EmumConstant.instorageDetailState.STORAGEING.getCode());
        instorageDetail.setFactoryCode(factoryCode);
        instorageDetailDAO.updateById(instorageDetail);
        carDAO.updateCarByCode(carCode,shelfCode,Long.valueOf(EmumConstant.carState.INSTORAGING.getCode()));
        return new PdaResult();
    }
    
    /**
     * 推荐库位同步到pad
     * @param shelfCode 库位编码
     * @param carCode 行车编码
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult recommendShelfSubmit(String shelfCode,String carCode) {
        if(StringUtils.isBlank(shelfCode)){
            return new PdaResult(1,"请选择库位！","");
        }
    	try {
    	    if (StringUtils.isNotBlank(carCode)&&!"null".equals(carCode)){
                Car car = carDAO.selectOne(new Car() {{
                    setCode(carCode);
                }});
                car.setMission(shelfCode);
                carDAO.updateById(car);
            }
		} catch (Exception e) {
			e.printStackTrace();
		}
    	
        return new PdaResult();
    }

    /**
     * 完成入库时，根据入库事务日期，判断是否需要弹框提示确认，如果线盘的报验时间是在当前月1号的8：30以前的，
     * @param date 事务时间
     * @param rfid rfid
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageinTiemCheck(String date, String rfid) {
        //上月的最后一天
        String laterMounthLastDay = DateUtils.getDay(DateUtils.getMounthLaterLastDay());
        //本月的第一天
        String currentMounthFirstDay = DateUtils.getDay(DateUtils.addDateDays(DateUtils.getMounthLaterLastDay(),1));
        /*//判断报验时间是否处于每月1号的00：00至08：30
        boolean inspectTimeOrNot = pdaDAO.findInspectNoTimeOrNot(rfid, currentMounthFirstDay) > 0;*/
        //判断报验时间是在每月1号的8点30之前的
        boolean inspectTimeOrNot = pdaDAO.findInspectNoTimeOrNot2(rfid, currentMounthFirstDay) > 0;
        //判断当前时间是否处于每月1号的00：00至15：00
        boolean limitTimeOrNot = DateUtils.belongCalendar(new Date(), DateUtils.stringToDate(currentMounthFirstDay+" 00:00:00",
                Constant.sdfTime), DateUtils.stringToDate(currentMounthFirstDay+" 15:00:00",Constant.sdfTime));
        //如果是特殊时期并且用户没有选择上月最后一天，那么弹框提示，否则不用弹框直接入库
        if (limitTimeOrNot && !Objects.equals(DateUtils.stringToDate(date, Constant.sdfDay),
                DateUtils.stringToDate(laterMounthLastDay, Constant.sdfDay)) && inspectTimeOrNot){
            return new PdaResult(1,"入库日期已默认修改为上月最后一天！",laterMounthLastDay);
        }else {
            return new PdaResult();
        }

    }

    /**
     * 完成入库
     * @param rfid rfid
     * @param shelfCode 库位编码
     * @param userId 用户id
     * @param date 事务时间
     * @param isCertificate 是否是合格证扫描：0不是。1是
     * @param factoryCode 厂区
     * @param warehouseCode 仓库
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageinStorageinSuccess(String rfid, String shelfCode, Long userId, String date, String isCertificate,
                                               String factoryCode, String warehouseCode) {
        //防止重复点击（这里qaCode必不可能为空，除非二次点击）
        if (org.apache.commons.lang3.StringUtils.isBlank(rfid)){
            return new PdaResult(1,"按钮已点击，请稍等","");
        }

        List<Shelf> lstShelf = shelfDAO.selectList(new EntityWrapper<Shelf>()
                .eq("CODE", shelfCode)
                .eq("FACTORYCODE", factoryCode)
                .eq("WAREHOUSECODE", warehouseCode));
        if (lstShelf==null || lstShelf.size()!=1){
            return new PdaResult(1,"该库位数据有误，请联系管理员查看！","");
        }
        Shelf shelf = lstShelf.get(0);

        //true是合格证扫描
    	boolean isCertificateFlag = "1".equals(isCertificate);
        InstorageDetail instorageDetail = instorageDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
        }}).get(0);
        Instorage instorage = instorageDAO.selectById(instorageDetail.getPId());
        List<StorageInfo> lstStorageInfo = storageInfoDAO.selectList(new EntityWrapper<StorageInfo>()
                .eq("QACODE", instorageDetail.getQaCode()));
        //如果存在了，则不能重复新增
        if(lstStorageInfo!=null && lstStorageInfo.size()>0) {
            return new PdaResult(1,"已存在，不能重复入库","");
        }

        List<FactoryArea> factorySerialnumList = factoryAreaDAO.selectByMap(new HashMap<String,Object>(1){{
            put("CODE", factoryCode);
        }});
        //流水号
        String serialnum = (factorySerialnumList.size()>0 && StringUtils.isNotBlank(factorySerialnumList.get(0).getSerialnum())) ?
                factorySerialnumList.get(0).getSerialnum() : "0000";
        serialnum = String.format("%04d", Integer.parseInt(serialnum) + 1);

        //更新流水号
        if(factorySerialnumList.size() > 0 && !isCertificateFlag) {
            FactoryArea factoryArea = factorySerialnumList.get(0);
            factoryArea.setSerialnum(serialnum);
            factoryAreaDAO.updateById(factoryArea);
        }

        //如果是勾选了“更换合格证扫描”，那么就从ebs查询获取盘号（因为更换合格证的其实已经是入库完成的，盘号已经生成并同步到了EBS，所以这里需要与EBS同步）
        if(isCertificateFlag) {
    		Map<String,Object> ebsMap = pdaDAO.getebsbatchno(instorageDetail.getQaCode());
    		if(ebsMap==null||ebsMap.get("LOT_NUMBER")==null||ebsMap.get("PAN_NUMBER")==null) {
                return new PdaResult(1, "同步EBS的盘号或批次号为空，请检查!", "");
            }

            instorageDetail.setBatchNo(ebsMap.get("LOT_NUMBER").toString());
            instorageDetail.setDishcode(ebsMap.get("PAN_NUMBER").toString());
    	}

        //如果是非更换合格证扫描，即正常扫描，那么需要在wms生成盘号
        Dish dish = null;
        if (StringUtils.isNotBlank(instorageDetail.getDishnumber())){
            dish = dishDAO.selectOne(new Dish() {{
                setCode(instorageDetail.getDishnumber());
            }});
        }
        //盘号：库位编码第一位字母+盘类型+盘大小+日期标识+流水号(虚拟盘除外，虚拟盘用盘具编码作为盘号)
        String drumno ;
        //零头库或者虚拟盘都不生成盘号
        if (dish == null || "1327100013".equals(dish.getCode()) || "F003".equals(warehouseCode)){
            drumno = "";
        }else{
            drumno = shelfCode.charAt(0)+ ("铁木盘".equals(dish.getDrumType()) ? Constant.STRING_ONE:"全木盘".equals(dish.getDrumType()) ?
            Constant.STRING_TWO : Constant.STRING_THREE)+new DecimalFormat("000").format(Long.parseLong(dish.getOuterDiameter()
            != null ? dish.getOuterDiameter() : "0")/10) + DateUtils.getDays().substring(2) + serialnum;
        }
        //入库日志
        InventoryIn inventoryIn = new InventoryIn();
        inventoryIn.setOrg(factoryCode);
        inventoryIn.setModel(instorageDetail.getDishnumber());
        inventoryIn.setDishtype(dish == null?"":dish.getDrumType());
        inventoryIn.setDishsize(dish == null?"":dish.getOuterDiameter());
        inventoryIn.setRfid(rfid);
        inventoryIn.setWarehousecode(warehouseCode);
        inventoryIn.setShelfcode(shelfCode);
        inventoryIn.setInStorageId(userId);
        inventoryIn.setOuterDiameter(dish==null?0:
                Long.parseLong(StringUtils.isNotBlank(dish.getOuterDiameter())?dish.getOuterDiameter():"0"));
        inventoryIn.setDrumType(isCertificate);
        inventoryIn.setMaterialcode(serialnum);
        inventoryIn.setMaterialname(drumno);
        inventoryIn.setQacode(instorageDetail.getQaCode());
        inventoryInDAO.insert(inventoryIn);

        //入库人
        String userno = userDAO.selectById(userId).getUsername();
        //调MES入库接口
        if(instorageDetail.getStoragetype() == 0) {
        	Map<String,Object> xmlMap = new HashMap<>();
        	xmlMap.put("orgid", factoryCode);
            xmlMap.put("busdate", date);
            xmlMap.put("userno", userno);
        	xmlMap.put("batches", new HashMap<String,Object>(){{
        		put("batch",new HashMap<String,Object>(3){{
        			put("batchno",instorageDetail.getBatchNo());
        			put("invlocation", shelf.getCodeComplete());
                    //成品电缆盘号
        			put("drumno", drumno);
        		}});
        	}});

            while (ConRunningMap.containsItem(EbsInterfaceEnum.FEMES001 + instorageDetail.getQaCode() + "PDA")){
                try {
                    TimeUnit.MILLISECONDS.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //把接口编码+质保号放到内存中
            ConRunningMap.addItem(EbsInterfaceEnum.FEMES001 + instorageDetail.getQaCode() + "PDA");
            interfaceDoServiceImpl.insertDo(EbsInterfaceEnum.FEMES001, "MES入库接口（生产入库）", JSONObject.toJSONString(xmlMap),
                    DateUtils.getTime(), instorageDetail.getQaCode(), instorageDetail.getBatchNo(),null,"");
            ConRunningMap.removeItem(EbsInterfaceEnum.FEMES001 + instorageDetail.getQaCode() + "PDA");
        }else if(instorageDetail.getStoragetype() == 1) {
            //销售退货入库
			Map<String,Object> params = new HashMap<>(1);
			params.put("line", new HashMap<String,Object>(12){{
				put("orgid",instorageDetail.getOrg());
                //物料编码
				put("itemnumber",instorageDetail.getMaterialCode());
                //客户id
				put("customerid",instorageDetail.getCustomerid());
                //员工编号
				put("employeenum",userno);
                //数量
                put("quantity",instorageDetail.getMeter());
                //事务处理日期
				put("transdate",date);
                //库位编码
				put("locatornum",shelf.getCodeComplete());
                //销售订单头id
				put("oeheaderid",instorageDetail.getOeheader());
                //销售订单行id
				put("oelineid",instorageDetail.getOeline());
                //批次号
				put("lotnumber",instorageDetail.getBatchNo());
                //质保号
                put("qacode",instorageDetail.getQaCode());
                //盘号
                put("dishcode",drumno);
			}});

            while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS024 + instorageDetail.getQaCode() + "PDA")){
                try {
                    TimeUnit.MILLISECONDS.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //把接口编码+质保号放到内存中
            ConRunningMap.addItem(EbsInterfaceEnum.FEWMS024 + instorageDetail.getQaCode() + "PDA");
            interfaceDoServiceImpl.insertDo(EbsInterfaceEnum.FEWMS024, "EBS接口-销售退货入库", JSONObject.toJSONString(params),
                    DateUtils.getTime(), instorageDetail.getQaCode(), instorageDetail.getBatchNo(),null, "");
            ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS024 + instorageDetail.getQaCode() + "PDA");
        }else if(instorageDetail.getStoragetype() == 2) {
            //外协采购入库
	    	Map<String,Object> params = new HashMap<>(1);
	    	params.put("line",new HashMap<String,Object>(9) {{
                //组织机构
	    		put("orgid",instorageDetail.getOrg());
                //质保号
	    		put("qacode",instorageDetail.getQaCode());
                //报验单号
	    		put("inspectno",instorageDetail.getInspectno());
                //入库仓库
	    		put("worehouse",warehouseCode);
                //库位
	    		put("location",shelf.getCodeComplete());
                //盘号
	    		put("panno",drumno);
                //批次号
	    		put("batchname",instorageDetail.getBatchNo());
                //事务处理日期
	    		put("trans_date",date);
                put("userno", userno);
	    	}});

            while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS025 + instorageDetail.getQaCode() + "PDA")){
                try {
                    TimeUnit.MILLISECONDS.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //把接口编码+质保号放到内存中
            ConRunningMap.addItem(EbsInterfaceEnum.FEWMS025 + instorageDetail.getQaCode() + "PDA");
            interfaceDoServiceImpl.insertDo(EbsInterfaceEnum.FEWMS025, "EBS接口-外采入库", JSONObject.toJSONString(params),
                    DateUtils.getTime(), instorageDetail.getQaCode(), instorageDetail.getBatchNo(),null, "");
            ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS025 + instorageDetail.getQaCode() + "PDA");
        }

        //不是扫描合格证的，需要更新盘号
        if(!isCertificateFlag) {
            instorageDetail.setDishcode(drumno);
        }
        instorageDetail.setShelfCode(shelfCode);
        instorageDetail.setInStorageId(userId);
        instorageDetail.setInstorageTime(new Date());
        instorageDetail.setFactoryCode(factoryCode);
        instorageDetail.setWarehouseCode(warehouseCode);
        instorageDetail.setState(EmumConstant.instorageDetailState.STORAGED.getCode());
        //登记台账
        List<Car> lstCar = carDAO.selectByMap(new HashMap<String, Object>(1){{
            put("CODE", instorageDetail.getCarCode());
        }});
        instorageDetail.setInstorageCarId(lstCar.size()>0?lstCar.get(0).getLoginer():null);
        instorageDetailDAO.updateById(instorageDetail);

        StorageInfo storageInfo = new StorageInfo();
        storageInfo.setMaterialCode(instorageDetail.getMaterialCode());
        storageInfo.setBatchNo(instorageDetail.getBatchNo());
        storageInfo.setQaCode(instorageDetail.getQaCode());
        storageInfo.setShelfCode(shelfCode);
        storageInfo.setWarehouseCode(instorageDetail.getWarehouseCode());
        storageInfo.setMeter(instorageDetail.getMeter());
        storageInfo.setRfid(instorageDetail.getRfid());
        storageInfo.setInStorageTime(new Date());
        storageInfo.setOrg(instorageDetail.getFactoryCode());
        storageInfo.setSalesCode(instorageDetail.getSalesCode());
        storageInfo.setSalesName(instorageDetail.getSalesName());
        storageInfo.setInStorageId(userId);
        storageInfo.setEntityNo(instorage!=null?instorage.getEntityNo():"");
        storageInfo.setOrderline(instorageDetail.getOrderline());
        storageInfo.setOrderno(instorageDetail.getOrdernum());
        storageInfo.setDishnumber(instorageDetail.getDishnumber());
        storageInfoDAO.insert(storageInfo);

        //恢复行车状态为可用
        carDAO.updateCarByCode(instorageDetail.getCarCode(),"", Long.valueOf(EmumConstant.carState.UNUSED.getCode()));
        //库位不可用
        shelfImpl.setShelfState(shelfCode, shelf.getFactoryCode(), shelf.getWarehouseCode(),0);
        return new PdaResult();
    }

    /**
     * 获取指定厂区仓库下指定仓库区域内的库位，并按照距离挂钩位置排序
     * @param warehouseCode 仓库编码
     * @param factoryCode 厂区编码
     * @param pageNo 页码
     * @param size 每页数量
     * @param code 库位模糊查询输入
     * @param carCode 行车编码
     * @return PdaResult 行车所在仓库区域的库位列表
     */
    @Override
    public PdaResult storageinEmptyShelf(String warehouseCode,String factoryCode,int pageNo,int size,String code, String carCode) {
        DeviceUwbRoute deviceUwbRoute = null;
        Car car = null;
        if (StringUtils.isNotBlank(carCode)){
            car = carDAO.selectList(new EntityWrapper<Car>().eq("CODE", carCode)).get(0);
            if (StringUtils.isNotBlank(car.getTag())){
                deviceUwbRoute = deviceUwbRouteDAO.selectList(new EntityWrapper<DeviceUwbRoute>().eq("TAG", car.getTag())).get(0);
            }
        }

        List<Shelf> lstUsefulShelf = pdaDAO.storageinEmptyShelf(new Page(pageNo, size), warehouseCode, factoryCode, code,
                car!=null && car.getWarehouseArea()!=null ? Arrays.asList(car.getWarehouseArea().split(",")) : new ArrayList<>());

    	if (deviceUwbRoute!=null){
            Float xsize = deviceUwbRoute.getXsize()*100;
            Float ysize = deviceUwbRoute.getYsize()*100;

            if(lstUsefulShelf!=null) {
                lstUsefulShelf.forEach(shelf -> shelf.setDistance(Math.sqrt(Math.pow((xsize - shelf.getMidxsize()) * 100 / 100, 2) +
                        Math.pow((ysize - shelf.getMidysize()) * 100 / 100, 2))));
                lstUsefulShelf.sort((a, b) -> Integer.compare((int) (a.getDistance() - b.getDistance()),0));
            }
        }

        return new PdaResult(lstUsefulShelf);
    }

    /**
     * 获取指定厂区仓库下的可用库位
     * @param warehouseCode 仓库编码
     * @param factoryCode 厂区编码
     * @param pageNo 页码
     * @param size 每页数量
     * @param code 库位模糊查询输入
     * @return PdaResult 库位列表
     */
    @Override
    public PdaResult selectNoCarShelf(String warehouseCode,String factoryCode,int pageNo,int size,String code) {
        return new PdaResult(pdaDAO.selectNoCarShelf(new Page(pageNo, size), warehouseCode, factoryCode, code));
    }
    
    /**
     * 完成入库真实库位选择(获取挂钩周围一圈最近的若干个库位)
     * @param pageNo 页码
     * @param size 每页数量
     * @param code 库位模糊查询输入
     * @param carCode 行车
     * @return PdaResult 行车所在仓库区域的库位列表
     */
    @Override
    public PdaResult getRealArroundShelf(int pageNo,int size,String code,String carCode) {
        Car car = carDAO.selectOne(new Car() {{
                setCode(carCode);
            }});

        List<Shelf> shelfList = StringUtils.isBlank(car.getTag()) ? pdaDAO.selectVisualShelf(new Page(pageNo, size), car.getWarehouseCode(),
                car.getFactoryCode(), code) : pdaDAO.getRealArroundShelf(new Page(pageNo, Constant.SIZE), code,
                Arrays.asList(car.getWarehouseArea().split(",")), car.getFactoryCode(), car.getWarehouseCode());
    	if (StringUtils.isNotBlank(car.getTag()) && shelfList!=null && shelfList.size()>0) {
            DeviceUwbRoute deviceUwbRoute = deviceUwbRouteDAO.selectList(new EntityWrapper<DeviceUwbRoute>()
                    .eq("TAG", car.getTag())).get(0);
            Float xsize = deviceUwbRoute.getXsize() * 100;
            Float ysize = deviceUwbRoute.getYsize() * 100;
            //设置距离挂钩的距离
            shelfList.forEach(shelf -> shelf.setDistance(Math.sqrt(Math.pow((xsize - shelf.getMidxsize())*100/100,2) +
                    Math.pow((ysize - shelf.getMidysize())*100/100, 2))));

            shelfList.sort((a, b) -> Integer.compare((int) (a.getDistance() - b.getDistance()),0));
            if (shelfList.size()>100){
                shelfList = shelfList.subList(0, 100);
            }
        }
        return new PdaResult(shelfList);
    }

    /**
     * 获取UWB所在库位(定位库位)
     * @param carCode 行车编码
     * @return PdaResult 定位库位
     */
    @Override
    public PdaResult getUwbShelf(String carCode) {
        if(StringUtils.isBlank(carCode)){
            return new PdaResult(1,"没有行吊，不能获取定位库位","");
        }
        Car car = carDAO.selectOne(new Car() {{
            setCode(carCode);
        }});
        List<DeviceUwbRoute> deviceUwbRouteList = deviceUwbRouteDAO.selectList(new EntityWrapper<DeviceUwbRoute>()
                .eq("TAG", car.getTag()));
        if(deviceUwbRouteList==null || deviceUwbRouteList.size()!=1){
            return new PdaResult(1, "该行车没有绑定UWB标签，不能使用此功能！", "");
        }

        DeviceUwbRoute deviceUwbRoute = deviceUwbRouteList.get(0);
        Float xsize = deviceUwbRoute.getXsize()*100;
        Float ysize = deviceUwbRoute.getYsize()*100;

        //获取坐落在库位区间内
        List<Shelf> shelfList = pdaDAO.getUwbShelf(xsize, ysize, Arrays.asList(car.getWarehouseArea().split(",")));
        //标签的点不在库位内部
        if(shelfList==null||shelfList.size()==0) {
            shelfList = shelfDAO.findAllShelfByArea(Arrays.asList(car.getWarehouseArea().split(",")));
            shelfList.sort((o1,o2)->
                Integer.compare((int)(Math.sqrt(Math.pow((xsize - o1.getMidxsize()), 2) + Math.pow((ysize - o1.getMidysize()), 2)) -
                Math.sqrt(Math.pow((xsize - o2.getMidxsize()), 2) + Math.pow((ysize - o2.getMidysize()), 2))),0));
        }
        Shelf shelf = shelfList.get(0);
        RealLocation realLocation = new RealLocation();
        realLocation.setXsize1(shelf.getXsize1());
        realLocation.setYsize1(shelf.getYsize1());
        realLocation.setXsize2(shelf.getXsize2());
        realLocation.setYsize2(shelf.getYsize2());
        realLocation.setCreatetime(new Date());
        realLocation.setRealx(xsize);
        realLocation.setRealy(ysize);
        realLocationDAO.insert(realLocation);

        return new PdaResult(shelf.getCode());
    }
    
    /**
     * 出库:选择行车
     * @param warehouseCode 仓库编码
     * @param factoryCode 厂区编码
     * @return PdaResult 行车列表
     */
    @Override
    public PdaResult storageoutStorageoutCar(String warehouseCode,String factoryCode) {
        return new PdaResult(carDAO.selectList(new EntityWrapper<Car>()
                .eq(StringUtils.isNotBlank(warehouseCode),"WAREHOUSECODE", warehouseCode)
                .eq(StringUtils.isNotBlank(factoryCode),"FACTORYCODE", factoryCode)));
    }

    /**
     * 扫描/输入，获取单个发货单
     * @param shipNo 发货单号
     * @param factoryCode 厂区
     * @param warehouseCode 仓库
     * @param carCode 航车
     * @return PdaResult 发货单信息
     */
    @Override
    public PdaResult findOutstorageByScan(String shipNo,String factoryCode,String warehouseCode,String carCode) {
        if (shipNo.length()!=10 && shipNo.length() != 12 && shipNo.length() != 17){
            return new PdaResult(1, "请输入完整的发货单号", "");
        }
        HashMap<String, Object> mapResult = new HashMap<>(2);
        List<OutStorage> lstOutStorage = outstorageDAO.selectList(new EntityWrapper<OutStorage>()
                .eq("SHIP_NO",shipNo.length() == 10 ? ("XSLKD20"+shipNo) : shipNo.length() == 12 ? ("XSLKD"+shipNo) : shipNo)
                .or().eq("SHIP_NO",shipNo.length() == 10 ? ("XSQKD20"+shipNo) : shipNo.length() == 12 ? ("XSQKD"+shipNo) : shipNo));
        if(lstOutStorage==null||lstOutStorage.size()!=1) {
            return new PdaResult(1, "系统中该发货单不存在，请联系管理员查看", "");
        }

        shipNo = lstOutStorage.get(0).getShipNo();
        OutStorage outStorage = pdaDAO.selectStorageByShipNo(shipNo);
        //根据发货单号查询详情是否已经全部出库完成
        outStorage.setStorageState(pdaDAO.findNoFinishOutstorageDetail(shipNo, factoryCode, warehouseCode)>0 ? "未完成" : "已完成");

        mapResult.put("outStorage", outStorage);
        //获取该发货单下的所有详情的所在库位以及出库情况
        mapResult.put("shelfList",pdaDAO.findOutstorageShelfs(shipNo, factoryCode, warehouseCode));

        return new PdaResult(mapResult);
    }

    /**
     * 发货：点击发货单，获取发货单及对应详情
     * @param shipNo 发货单号
     * @param warehouseCode 仓库
     * @param userId 用户
     * @param factoryCode 厂区
     * @param carCode 行车
     * @return PdaResult 发货明细列表,发货单号,营销经理
     */
    @Override
    public PdaResult storageoutDetailList(String shipNo, String warehouseCode, Long userId, String factoryCode,String carCode) {
        if (shipNo.length()!=10 && shipNo.length()!=12 && shipNo.length()!=17){
            return new PdaResult(1, "请输入完整的发货单号", "");
        }

        List<OutStorage> lstOutStorage = outstorageDAO.selectList(new EntityWrapper<OutStorage>()
                .eq("SHIP_NO",shipNo.length()==10 ? ("XSLKD20"+shipNo) : shipNo.length()==12 ? ("XSLKD"+shipNo) : shipNo)
                .or().eq("SHIP_NO",shipNo.length()==10 ? ("XSQKD20"+shipNo) : shipNo.length()==12 ? ("XSQKD"+shipNo) : shipNo));

        return new PdaResult(new HashMap<String, Object>() {{
            put("storage", pdaDAO.selectStorageByShipNo(lstOutStorage.get(0).getShipNo()));
            //根据提货单号、厂区、仓库,查询该提货单下的明细
            put("detailList", pdaDAO.selectOutStorageDetail(shipNo,factoryCode,warehouseCode));
        }});
    }

    /**
     * 扫描物料rfid=开始出库,更改状态拣选中  (1:生效  2:拣选中  3:拣选完成 )
     * @param rfid rfid
     * @param carCode 行车
     * @param user_id 用户
     * @param shipNo 发货单
     * @param barcode 二维码
     * @param barcodeType 扫码类型
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageoutDetailClick1(String rfid,String carCode,Long user_id,String shipNo,String barcode,String barcodeType) {
        List<OutStorageDetail> lstOutStorageDetail=outStorageDetailDAO.selectOutStorageDetailByShipNoAndId(shipNo,rfid,barcode,barcodeType);
        if (lstOutStorageDetail != null && lstOutStorageDetail.size() == 1) {
        	OutStorageDetail outStorageDetail = lstOutStorageDetail.get(0);
        	if (outStorageDetail.getState()==3||outStorageDetail.getState()==4){
                return new PdaResult(1,"该盘货物已经完成了扫码出库！","");
            }
            List<StorageInfo> lstStorageInfo=storageInfoDAO.selectList(new EntityWrapper<StorageInfo>()
                    .eq("QACODE",outStorageDetail.getQaCode()));
        	if(lstStorageInfo==null||lstStorageInfo.size()==0) {
                return new PdaResult(1,"库存中没有该盘货物，联系管理员查看！","");
            }

            outStorageDetail.setCarCode(carCode);
            //扫货时间
            outStorageDetail.setStartpicktime(new Date());
            //出库中
            outStorageDetail.setState(EmumConstant.outstorageDetailState.OUTSTORAGING.getCode());
            outStorageDetail.setScantime(new Date());
            outStorageDetailDAO.updateById(outStorageDetail);
            //更新行车状态
            carDAO.updateCarByCode(carCode, outStorageDetail.getShelfCode(), Long.valueOf(EmumConstant.carState.OUTSTORAGING.getCode()));

            return new PdaResult();
        } else {
            return lstOutStorageDetail==null||lstOutStorageDetail.size()==0?new PdaResult(1,"该提货单没有对应此线盘信息",""):
                    new PdaResult(1,"该盘货已经完成出库，请勿重复扫描","");
        }
    }

    /**
     * 排序界面进入单条明细界面扫描物料rfid=开始出库,更改状态拣选中  (1:生效  2:拣选中  3:拣选完成  4:预出库)
     * @param rfid rfid
     * @param carCode 行车
     * @param userId 用户
     * @param shipNo 提货单
     * @param barcode 二维码
     * @param barcodeType 扫描类型
     * @param instorageDetailId 发货明细主键
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageoutSortScan(String rfid, String carCode, Long userId, String shipNo, String barcode, String barcodeType,
                                        Long instorageDetailId) {
        List<OutStorageDetail> lstOutStorageDetail=outStorageDetailDAO.selectOutStorageDetailByShipNoAndId(shipNo,rfid,barcode,barcodeType);
        if (lstOutStorageDetail != null && lstOutStorageDetail.size() == 1) {
            OutStorageDetail outStorageDetail = lstOutStorageDetail.get(0);
            if (outStorageDetail.getState()==3||outStorageDetail.getState()==4){
                return new PdaResult(1,"该盘货物已经完成了扫码出库！","");
            }

            outStorageDetail.setCarCode(carCode);
            //扫货时间
            outStorageDetail.setStartpicktime(new Date());
            outStorageDetail.setState(EmumConstant.outstorageDetailState.OUTSTORAGING.getCode());
            outStorageDetail.setScantime(new Date());
            outStorageDetailDAO.updateById(outStorageDetail);
            //更新行车状态
            carDAO.updateCarByCode(carCode, outStorageDetail.getShelfCode(), Long.valueOf(EmumConstant.carState.OUTSTORAGING.getCode()));

            return new PdaResult();
        } else {
            return lstOutStorageDetail == null ? new PdaResult(1,"该提货单没有对应此线盘信息","") :
                    new PdaResult(1,"该盘货已经完成出库，请勿重复扫描","");
        }
    }

    /**
     * 出库-完成出库窗口中取消出库
     * @param qaCode 质保号
     * @param shipNo 发货单号
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult cancelOutStorage(String qaCode, String shipNo) {
        //防止重复点击（这里qaCode必不可能为空，除非二次点击）
        if (org.apache.commons.lang3.StringUtils.isBlank(qaCode)){
            return new PdaResult(1,"按钮已点击，请稍等","");
        }

        OutStorageDetail outStorageDetail = outStorageDetailDAO
                .selectOutStorageDetailByShipNoAndId(shipNo,"",qaCode,"0").get(0);
    	outStorageDetail.setState(EmumConstant.outstorageDetailState.UNOUTSTORAGE.getCode());
    	outStorageDetail.setCarCode("");
    	outStorageDetailDAO.updateById(outStorageDetail);
        //更新行车状态
        carDAO.updateCarByCode(outStorageDetail.getCarCode(), "", Long.valueOf(EmumConstant.carState.UNUSED.getCode()));

        return new PdaResult();
    }
    
    /**
     * 完成出库-判断发货单米数与库存不相符，弹窗提示。
     * @param qaCode 质保号
     * @param type 【废弃】（出库类型：1全部出库，2按米出库）
     * @param shipNo 提货单号
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult judgeOutmeter(String qaCode,String type,String shipNo) {
        if (org.apache.commons.lang3.StringUtils.isBlank(qaCode)){
            return new PdaResult(1,"按钮已点击，请稍等","");
        }
        OutStorageDetail outStorageDetail = outStorageDetailDAO
                .selectOutStorageDetailByShipNoAndId(shipNo,"",qaCode,"0").get(0);
        StorageInfo storageInfo = storageInfoDAO.selectList(new EntityWrapper<StorageInfo>()
                .eq("QACODE",outStorageDetail.getQaCode())).get(0);

        return Double.valueOf(outStorageDetail.getMeter()).intValue() != Double.valueOf(storageInfo.getMeter()).intValue() ?
                new PdaResult(0,"库存米数"+storageInfo.getMeter()+"，发货米数"+outStorageDetail.getMeter()+"，是否出库？","1") :
                //不需要弹窗，直接走到storageoutDetailClick2方法中
                new PdaResult(0,"","0");
    }

    /**
     * 完成预出库 发货：点击完成出库,更改状态为预出库(1:生效  2:拣货中  3:出库完成  4预出库)
     * @param qaCode 质保号
     * @param userId 用户主键
     * @param type [废弃]（出库类型：1全部出库，2按米出库）
     * @param shipNo 提货单
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageoutDetailClick2(String qaCode,Long userId,String type,String shipNo) {
        if (org.apache.commons.lang3.StringUtils.isBlank(qaCode)){
            return new PdaResult(1,"按钮已点击，请稍等","");
        }

        OutStorageDetail outStorageDetail = outStorageDetailDAO
                .selectOutStorageDetailByShipNoAndId(shipNo,"",qaCode,"0").get(0);
        //预出库时间
        outStorageDetail.setStartStorageTime(new Date());
        //预出库人（下架人）
        outStorageDetail.setStartstorageid(userId);
        //状态设为下架状态
        outStorageDetail.setState(EmumConstant.outstorageDetailState.OUTSTORAGE_PREPARE.getCode());
        //更新出库明细表
        outStorageDetailDAO.updateById(outStorageDetail);

        List<Split> lstSplit = splitDAO.selectList(new EntityWrapper<Split>().eq("BATCH_NO", outStorageDetail.getBatchNo()));
        //先看拆分表有没有该线盘信息，如果有，修改拆分表的库存状态
        if (lstSplit.size()>0){
            lstSplit.forEach(split -> {
                //修改拆分表库存状态
                split.setState(EmumConstant.storageInfoState.PREOUT.getCode());
                splitDAO.updateById(split);
                //更新库位状态：释放库位
                shelfImpl.setShelfState(split.getShelfCode(), split.getOrg(), split.getWarehouseCode(),
                        EmumConstant.sheflState.AVAILABLE.getCode());
            });
        }else {
            StorageInfo storageInfo = storageInfoDAO.selectList(new EntityWrapper<StorageInfo>()
                    .eq("QACODE",outStorageDetail.getQaCode())).get(0);
            //更新库存状态为预出库
            storageInfo.setState(EmumConstant.storageInfoState.PREOUT.getCode());
            storageInfoDAO.updateById(storageInfo);
            if (Float.parseFloat(storageInfo.getMeter())-Float.parseFloat(outStorageDetail.getMeter())==0){
                //更新库位状态：释放库位
                shelfImpl.setShelfState(storageInfo.getShelfCode(), storageInfo.getOrg(), storageInfo.getWarehouseCode(),
                        EmumConstant.sheflState.AVAILABLE.getCode());
            }
        }

        //更新行车状态
        carDAO.updateCarByCode(outStorageDetail.getCarCode(), "", Long.valueOf(EmumConstant.carState.UNUSED.getCode()));

        //获取该发货单下的所有发货明细的状态
        String states = outStorageDetailDAO.getState(outStorageDetail.getPId());
        return new PdaResult(0, "成功", !states.contains("1") && !states.contains("2") ? "1" : "");
    }

    /**
     * 完成出库 发货：点击完成出库,更改状态为出库完成(1:生效  2:拣货中  3:出库完成  4预出库)
     * @param qaCode 质保号
     * @param userId 用户主键
     * @param type [废弃]（出库类型：1全部出库，2按米出库）
     * @param shipNo 提货单
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult storageoutConfirm(String qaCode,Long userId,String type,String shipNo) {
        if (org.apache.commons.lang3.StringUtils.isBlank(qaCode)){
            return new PdaResult(1,"按钮已点击，请稍等","");
        }

        OutStorageDetail outStorageDetail = outStorageDetailDAO
                .selectOutStorageDetailByShipNoAndId(shipNo,"",qaCode,"0").get(0);
        //调出库接口
        Map<String,Object> xmlMap = new HashMap<>(1);
        OutStorage outStorage = outstorageDAO.selectById(outStorageDetail.getPId());
        xmlMap.put("line", new HashMap<String, Object>(5) {{
            //纯出库
            put("type", 1);
            put("printcode", "");
            put("outno", outStorage.getShipNo());
            put("outtime", DateUtils.getTime());
            put("userno", userDAO.selectById(userId).getUsername());
            put("batchs",new HashMap<String,Object>(1){{
                put("batch",new HashMap<String,Object>(2){{
                    put("qacode", outStorageDetail.getQaCode());
                    put("deliverno", outStorageDetail.getStartstorageid() == null ? userDAO.selectById(userId).getUsername() :
                            userDAO.selectById(outStorageDetail.getStartstorageid()).getUsername());
                }});
            }});
        }});

        while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS002 + outStorageDetail.getQaCode() + "PDA")){
            try {
                TimeUnit.MILLISECONDS.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //把接口编码+质保号放到内存中
        ConRunningMap.addItem(EbsInterfaceEnum.FEWMS002 + outStorageDetail.getQaCode() + "PDA");
        interfaceDoServiceImpl.insertDo(EbsInterfaceEnum.FEWMS002, "出库", JSONObject.toJSONString(xmlMap), DateUtils.getTime(),
                outStorageDetail.getQaCode(), outStorageDetail.getBatchNo(),null,outStorage.getShipNo());
        ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS002 + outStorageDetail.getQaCode() + "PDA");

        //先看拆分表有没有该线盘信息，如果有，再判断拆分的米数是否复合出库米数，如果符合，更新拆分表库存
        Split split = splitDAO.selectOne(new Split(){{
            setBatchNo(outStorageDetail.getBatchNo());
        }});
        //如果拆分表有这个批次，那么就是已经分盘过的出库
        if (split!=null){
            //已出库
            split.setState(4);
            splitDAO.updateById(split);
            //释放库位
            shelfImpl.setShelfState(split.getShelfCode(),split.getOrg(),split.getWarehouseCode(),EmumConstant.sheflState.AVAILABLE.getCode());
        }else {
            //如果拆分表没有，那么就要从库存中去扣减
            StorageInfo storageInfo = storageInfoDAO.selectList(new EntityWrapper<StorageInfo>()
                    .eq("QACODE",outStorageDetail.getQaCode())).get(0);
            //剩余米数
            String leftMeter = String.valueOf(Float.parseFloat(storageInfo.getMeter()) - Float.parseFloat(outStorageDetail.getMeter()));
            //全部出库
            if ("0".equals(leftMeter) || "0.0".equals(leftMeter)) {
                shelfImpl.setShelfState(storageInfo.getShelfCode(),storageInfo.getOrg(),storageInfo.getWarehouseCode(),
                        EmumConstant.sheflState.AVAILABLE.getCode());
                storageInfoDAO.deleteById(storageInfo.getId());
            } else {
                //按米出
                storageInfo.setMeter(leftMeter);
                storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
                storageInfoDAO.updateById(storageInfo);
            }
        }

        //恢复行车状态为可用
        carDAO.updateCarByCode(outStorageDetail.getCarCode(), "", Long.valueOf(EmumConstant.carState.UNUSED.getCode()));

        //确认出库时间
        outStorageDetail.setOutStorageTime(new Date());
        //确认出库人
        outStorageDetail.setOutStorageId(userId);
        List<Car> lstCar = carDAO.selectByMap(new HashMap<String, Object>(1){{
            put("CODE",outStorageDetail.getCarCode());
        }});
        if (lstCar.size()>0){
            outStorageDetail.setOutcarerid(lstCar.get(0).getLoginer());
        }
        outStorageDetail.setState(EmumConstant.outstorageDetailState.OUTSTORAGED.getCode());
        //更新出库明细表
        outStorageDetailDAO.updateById(outStorageDetail);
        //获取该发货单下的所有发货明细的状态
        String states = outStorageDetailDAO.getState(outStorageDetail.getPId());
        return new PdaResult(0, "成功", !states.contains("1") && !states.contains("2") ? "1" : "");
    }

    /**
     * 划单扫码，扫提货单，撤销出库扫描提货单
     * @param shipNo 提货单号
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult revokeOustroageScan(String shipNo) {
        if (shipNo.length()!=10 && shipNo.length() != 12 && shipNo.length() != 17){
            return new PdaResult(1, "请输入完整的发货单号", "");
        }
        List<OutStorage> lstOutStorage = outstorageDAO.selectList(new EntityWrapper<OutStorage>()
                .eq("SHIP_NO",shipNo.length() == 10 ? ("XSLKD20"+shipNo) : shipNo.length() == 12 ? ("XSLKD"+shipNo) : shipNo)
                .or().eq("SHIP_NO",shipNo.length() == 10 ? ("XSQKD20"+shipNo) : shipNo.length() == 12 ? ("XSQKD"+shipNo) : shipNo));
        if(lstOutStorage==null||lstOutStorage.size()!=1) {
            return new PdaResult(1, "系统中该发货单不存在，请联系管理员查看", "");
        }

        return new PdaResult(lstOutStorage.get(0).getShipNo());
    }

    /**
     * 划单扫码，扫物料，撤销出库扫描物料
     * @param rfid rfid
     * @param barcode 二维码信息
     * @param barcodeType 二维码类型
     * @param shipNo 提货单号
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult revokeOustroageDetailScan(String rfid, String barcode, String barcodeType, String shipNo) {
        List<OutStorageDetail> lstOutStorageDetail=outStorageDetailDAO.selectOutStorageDetailByShipNoAndId(shipNo,rfid,barcode,barcodeType);
        return lstOutStorageDetail==null || lstOutStorageDetail.size()==0 ? new PdaResult(1, "该货物不属于此发货单！", "") :
                new PdaResult(lstOutStorageDetail.get(0));
    }

    /**
     * 划单提交,撤销出库确认
     * @param map 参数
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult revokeOustroageDetailConfirm(Map<String,Object> map) {
        if (map == null || map.get("storageInfoRfids") == null || map.get("shipNo") == null){
            return new PdaResult(1, "参数异常，请检查", "");
        }

        map.put("lstRfid",map.get("storageInfoRfids"));
        List<OutStorageDetail> lstOutStorageDetail = outStorageDetailDAO.selectOutStorageDetailByShipNoAndRfids(map);
        if(lstOutStorageDetail==null || lstOutStorageDetail.size()==0){
            return new PdaResult(1, "系统中没有此货物数据，请联系管理员核查！", "");
        }
        lstOutStorageDetail.forEach(outStorageDetail -> {
            //预出库时间
            outStorageDetail.setStartStorageTime(null);
            //预出库人（下架人）
            outStorageDetail.setStartstorageid(null);
            //状态设为未出库
            outStorageDetail.setState(EmumConstant.outstorageDetailState.UNOUTSTORAGE.getCode());
            //更新出库明细表
            outStorageDetailDAO.updateById(outStorageDetail);

            splitDAO.selectList(new EntityWrapper<Split>().eq("QACODE", outStorageDetail.getQaCode()))
                    .stream().filter(split -> Float.parseFloat(split.getMeter()) == Float.parseFloat(outStorageDetail.getMeter()))
                    .collect(Collectors.toList()).forEach(split -> {
                split.setState(EmumConstant.storageInfoState.NORMAL.getCode());
                splitDAO.updateById(split);
            });

            //更新库存状态
            List<StorageInfo> lstStorageInfo=storageInfoDAO.selectList(new EntityWrapper<StorageInfo>()
                    .eq("QACODE",outStorageDetail.getQaCode()));
            if(lstStorageInfo.size()>0){
                StorageInfo storageInfo = lstStorageInfo.get(0);
                storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
                storageInfoDAO.updateById(storageInfo);
            }
        });

        return new PdaResult();
    }

    /**
     * 根据输入的车牌号获取发货单
     * @param carNumber 车牌号
     * @param factoryCode 厂区
     * @param warehouseCode 仓库
     * @param carCode 航车
     * @return List<Map<String,Object>> 发货单号集合
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult getOutstorageListByCarNumber(String carNumber,String factoryCode,String warehouseCode,String carCode) {
        List<Map<String,Object>> lstmapebs = outstorageDAO.getOutstorageListByCarNumber(carNumber);
        List<String> lstShipNo = new ArrayList<>();
        if(lstmapebs!=null) {
            lstmapebs.forEach(map -> lstShipNo.add((String) map.get("PICKINGSLIPNUMBER")));
        }

        if(lstShipNo.size()>0){
            List<OutStorage> lstOutStorage = outstorageDAO.selectOutstorageListAndDetailStateByShipNos(lstShipNo,factoryCode,warehouseCode);
            if (lstOutStorage!=null) {
                //小：未完成
                int j = 0;
                //大：已完成
                int k = 100;
                for (OutStorage outStorage : lstOutStorage) {
                    //提货单整体是否完成校验
                    if (StringUtils.isNotBlank(outStorage.getStorageState())) {
                        if (outStorage.getStorageState().contains(EmumConstant.outstorageDetailState.OUTSTORAGING.getCode().toString()) ||
                            outStorage.getStorageState().contains(EmumConstant.outstorageDetailState.UNOUTSTORAGE.getCode().toString())) {
                            outStorage.setStorageState("未完成");
                            outStorage.setSortNumber(j++);
                        } else {
                            outStorage.setStorageState("已完成");
                            outStorage.setSortNumber(k++);
                        }
                    } else {
                        outStorage.setStorageState("");
                        outStorage.setSortNumber(500);
                    }
                    //获取该发货单下的所有详情的所在库位以及出库情况
                    outStorage.setLstmap(pdaDAO.findOutstorageShelfs(outStorage.getShipNo(), factoryCode, warehouseCode));
                }
                lstOutStorage.sort(Comparator.comparingInt(OutStorage::getSortNumber));
            }

            return new PdaResult(lstOutStorage);
        }else{
            return new PdaResult(1, "该车牌下没有发货单数据", "");
        }
    }

    /**
     * 根据发货单号获取对应厂区、仓库、航车区域下的已经完成的和所有的出库明细的数量
     * @param shipnoJsonString 发货单
     * @param factoryCode 厂区
     * @param warehouseCode 仓库
     * @param carCode 航车
     * @return Map<String,Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult getNumberByShipNo(String shipnoJsonString,String factoryCode,String warehouseCode,String carCode){
        JSONArray shipnojsonarray = JSONArray.fromObject(shipnoJsonString);
        List<String> shipNoList = new LinkedList<>();
        shipnojsonarray.forEach(shipno-> shipNoList.add((String) shipno));

        //根据发货单集合获取发货单主键集合
        List<Long> outStorageIdList = pdaDAO.selectOutstorageIdListByShipNo(shipNoList);
        return new PdaResult(new HashMap<String,Object>(){{
            //总数
            put("totalNum", outStorageDetailDAO.getOutstorageDetailTotalNum(outStorageIdList, factoryCode, warehouseCode));
            //已完成数量
            put("completeNum", outStorageDetailDAO.getOutstorageDetailCompleteNum(outStorageIdList, factoryCode, warehouseCode));
        }});
    }

    /**
     * 发货主界面排序按钮
     * @param shipnoJsonString 发货单
     * @param factoryCode 厂区编码
     * @param warehouseCode 仓库编码
     * @param carCode 航车编码
     * @param carNo 车牌号
     * @return Map<String,Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult sortOutstorageDetail(String shipnoJsonString,String factoryCode,String warehouseCode,String carCode,String carNo){
        List<Map<String,Object>> lstMapEBS = new ArrayList<>();
        List<String> lstShipNo = new ArrayList<>();
        if (StringUtils.isNotBlank(carNo)){
            lstMapEBS = outstorageDAO.getOutstorageListByCarNumber(carNo);
        }

        if (lstMapEBS!=null){
            lstMapEBS.forEach(map-> lstShipNo.add((String)map.get("PICKINGSLIPNUMBER")));
        }

        JSONArray shipNoJSONArray = JSONArray.fromObject(shipnoJsonString);
        List<String> shipNoList = new LinkedList<>();
        shipNoJSONArray.forEach(shipno-> shipNoList.add((String) shipno));
        shipNoList.addAll(lstShipNo);

        return new PdaResult(shipNoList.size() == 0 ? new ArrayList<>() :
                pdaDAO.sortOutstorageDetail(pdaDAO.selectOutstorageIdListByShipNo(shipNoList), factoryCode, warehouseCode));
    }

    /**
     * 点击排序后的明细，跳转到单一明细界面
     * @param instorageDetailId 发货明细主键
     * @param shipNo 提货单号
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult clickSoloOutStorageDetail(Long instorageDetailId, String shipNo) {
        return new PdaResult(pdaDAO.findSortSoloByStorageInfoId(instorageDetailId, shipNo).get(0));
    }

    /**
     * 发货主界面刷新按钮
     * @param shipnoJsonString 发货单
     * @param carNo 车牌号
     * @param factoryCode 厂区
     * @param warehouseCode 仓库
     * @param carCode 行车
     * @return Map<String,Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult refreshOutstorage(String shipnoJsonString, String carNo, String factoryCode, String warehouseCode, String carCode){
        List<Map<String,Object>> lstMapEBS = new ArrayList<>();
        List<String> lstShipNo = new ArrayList<>();
        if (StringUtils.isNotBlank(carNo)){
            lstMapEBS = outstorageDAO.getOutstorageListByCarNumber(carNo);
        }

        if (lstMapEBS!=null){
            lstMapEBS.forEach(map->{
                lstShipNo.add((String)map.get("PICKINGSLIPNUMBER"));
            });
        }

        JSONArray shipNoJSONArray = JSONArray.fromObject(shipnoJsonString);
        List<String> shipNoList = new LinkedList<>();
        shipNoJSONArray.forEach(shipno-> shipNoList.add((String) shipno));

        lstShipNo.addAll(shipNoList);

        if(lstShipNo.size()>0){
            //根据车牌和显示的提货单获取
            List<OutStorage> lstOutStorage = outstorageDAO.selectOutstorageListAndDetailStateByShipNos(lstShipNo,factoryCode,warehouseCode);
            if (lstOutStorage!=null) {
                //小：未完成
                int j = 0;
                //大：已完成
                int k = 100;
                for (OutStorage outStorage : lstOutStorage) {
                    //提货单整体是否完成校验
                    if (StringUtils.isNotBlank(outStorage.getStorageState())) {
                        if (outStorage.getStorageState().contains(EmumConstant.outstorageDetailState.OUTSTORAGING.getCode().toString()) ||
                            outStorage.getStorageState().contains(EmumConstant.outstorageDetailState.UNOUTSTORAGE.getCode().toString())) {
                            outStorage.setStorageState("未完成");
                            outStorage.setSortNumber(j++);
                        } else {
                            outStorage.setStorageState("已完成");
                            outStorage.setSortNumber(k++);
                        }
                    } else {
                        outStorage.setStorageState("");
                        outStorage.setSortNumber(500);
                    }
                    //获取该发货单下的所有详情的所在库位以及出库情况
                    outStorage.setLstmap(pdaDAO.findOutstorageShelfs(outStorage.getShipNo(), factoryCode, warehouseCode));
                }
                lstOutStorage.sort(Comparator.comparingInt(OutStorage::getSortNumber));
            }

            return new PdaResult(lstOutStorage);
        }else{
            return new PdaResult(1, "该车牌下没有发货单数据", "");
        }
    }

    /**
     * 物资流转单打印
     * @param carNo 车牌号
     * @param factoryCode 厂区
     * @param transferFactoryCode 流转厂
     * @return Map<String,Object>
     */
    @Override
    public PdaResult wzlzPrint(String carNo, String factoryCode, String transferFactoryCode){
        if (StringUtils.isBlank(carNo)){
            return new PdaResult(1, "请输入车牌号！", "");
        }
        if (StringUtils.isBlank(factoryCode)){
            return new PdaResult(1, "请选择厂区！", "");
        }
        if (StringUtils.isBlank(transferFactoryCode)){
            return new PdaResult(1, "请选择流转厂！", "");
        }
        //打印
        exchangePrintDetailServiceImpl.printWzlz(carNo,factoryCode,transferFactoryCode);
        return new PdaResult();
    }

    /**
     * 调拨扫描库存
     * @param rfid rfid
     * @param userId 用户主键
     * @param barcode 二维码
     * @param barcodeType 二维码类型
     * @return PdaResult 库存列表
     */
    @Override
    public PdaResult alloStorageInfoList(String rfid, Long userId, String barcode, String barcodeType) {
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("barcode", barcode);
        queryMap.put("barcodeType", barcodeType);
        queryMap.put("rfid", rfid);
        StorageInfo storageinfo = pdaDAO.findStorageInfoByqbr(queryMap);
        if (storageinfo == null) {
            return new PdaResult(1, "库存暂无该物料,请联系管理员查看", "");
        }
        //该物料存在于移库单中，且还未完成
        if (allocationDetailDAO.selectCount(new EntityWrapper<AllocationDetail>()
                .eq("BATCH_NO",storageinfo.getBatchNo())
                .in("STATE","1,2,3,4"))>0){
            return new PdaResult(1, "该线盘处在其他调拨任务中，请先完成再添加", "");
        }

        return new PdaResult(storageinfo);
    }

    /**
     * 点击提交，生成调拨单
     * @param map 入参：inWarehouseCode(调入仓库code),outWarehouseCode(调出仓库code),storageInfoRfids（库存列表id）,userId(用户id),
     *            inFactoryCode(调入厂区),outFactoryCode(调出厂区)
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult alloAdd(Map<String, Object> map) {
        if (map == null || map.get("inWarehouseCode") == null || map.get("outWarehouseCode") == null || map.get("userId") == null
                || map.get("storageInfoRfids") == null || map.get("inFactoryCode")==null || map.get("outFactoryCode") == null){
            return new PdaResult(1, "输入调拨参数异常，请检查", "");
        }

        String inWarehouseCode = (String)map.get("inWarehouseCode");
        String outWarehouseCode = (String)map.get("outWarehouseCode");
        String inFactoryCode = (String)map.get("inFactoryCode");
        String outFactoryCode = (String)map.get("outFactoryCode");
        Long userId = Long.valueOf(map.get("userId").toString());
        @SuppressWarnings("unchecked")
        List<String> rfids = (List<String>) map.get("storageInfoRfids");

        String serial = new DecimalFormat("0000").format(allocationDAO.selectLatestAllocation() + 1);
        String alloCode = "DB" + DateUtils.longToString2(System.currentTimeMillis()) + serial;
        Allocation allocation = new Allocation();
        allocation.setInWarehouseCode(inWarehouseCode);
        allocation.setOutWarehouseCode(outWarehouseCode);
        allocation.setInWarehouseId(warehouseDAO.selectByMap(new HashMap<String,Object>(2){{
            put("FACTORYCODE", inFactoryCode);
            put("CODE", inWarehouseCode);
        }}).get(0).getId());
        allocation.setOutWarehouseId(warehouseDAO.selectByMap(new HashMap<String,Object>(2){{
            put("FACTORYCODE", outFactoryCode);
            put("CODE", outWarehouseCode);
        }}).get(0).getId());
        allocation.setMoveTime(new Date());
        allocation.setUserId(userId);
        allocation.setState(EmumConstant.locationChangeStatus.START_CHANGE_OUT.getCode());
        allocation.setAllCode(alloCode);
        allocation.setFactoryCode(outFactoryCode);
        allocation.setInFactoryCode(inFactoryCode);
        allocationDAO.insert(allocation);
        moveStorageDAO.updateSerial(serial,"allo");

        rfids.forEach(rfid -> {
            StorageInfo storageInfo = storageInfoDAO.selectOne(new StorageInfo() {{
                setRfid(rfid);
            }});
            storageInfo.setState(EmumConstant.storageInfoState.LOCKING.getCode());
            storageInfoDAO.updateById(storageInfo);

            AllocationDetail allocationDetail = new AllocationDetail();
            allocationDetail.setMaterialCode(storageInfo.getMaterialCode());
            allocationDetail.setMeter(storageInfo.getMeter());
            allocationDetail.setQaCode(storageInfo.getQaCode());
            allocationDetail.setRfid(storageInfo.getRfid());
            allocationDetail.setPId(allocation.getId());
            allocationDetail.setBatchNo(storageInfo.getBatchNo());
            allocationDetail.setOutShelfCode(storageInfo.getShelfCode());
            allocationDetail.setInWarehouseCode(inWarehouseCode);
            allocationDetail.setOutWarehouseCode(outWarehouseCode);
            allocationDetail.setOrg(storageInfo.getOrg());
            allocationDetail.setSalesCode(storageInfo.getSalesCode());
            allocationDetail.setSalesName(storageInfo.getSalesName());
            allocationDetail.setEntityNo(storageInfo.getEntityNo());
            allocationDetail.setDishnumber(storageInfo.getDishnumber());
            allocationDetailDAO.insert(allocationDetail);
        });
        return new PdaResult();
    }

    /**
     * 返回所有未完成的主表信息
     * @param userId 用户主键
     * @return PdaResult 调拨单主表列表
     */
    @Override
    public PdaResult alloSelectAllUndo(Long userId) {
        return new PdaResult(pdaDAO.selectAllAllocation(Arrays.asList(userDAO.selectById(userId).getFactoryCode().split(","))));
    }

    /**
     * 返回所有未完成调拨出库的主表信息
     * @param userId 用户主键
     * @return PdaResult 调拨单主表列表
     */
    @Override
    public PdaResult alloSelectPartUndo(Long userId) {
        return new PdaResult(pdaDAO.alloSelectPartUndo(Arrays.asList(userDAO.selectById(userId).getFactoryCode().split(","))));
    }

    /**
     * 获取调拨任务
     * @param id 调拨主表ID
     * @return PdaResult 详情列表
     */
    @Override
    public PdaResult alloSelectDetailById(Long id) {
        return new PdaResult(pdaDAO.alloSelectDetailById(id));
    }

    /**
     * 调拨出库，进入调拨出库单展示列表后，选择行车
     * @param id 调拨单表主键
     * @param carCode 行车编码
     * @return PdaResult详情列表
     */
    @Override
    public PdaResult alloMissionToCar(Long id,String carCode) {
        /*String shelfCodes = "";
        Car car = carDAO.selectOne(new Car() {{
            setCode(carCode);
        }});

        List<AllocationDetail> lstAllocationDetail = allocationDetailDAO.selectList(new EntityWrapper<AllocationDetail>()
                .eq("PID", id).in("STATE", "1,2")
                .addFilter("OUTSHELFCODE LIKE {0}", car.getWarehouseArea()+"%"));

        if (lstAllocationDetail!=null){
            for (AllocationDetail allocationDetail : lstAllocationDetail) {
                shelfCodes += allocationDetail.getOutShelfCode() + ",";
            }
        }

        car.setMission(shelfCodes);
        carDAO.updateById(car);*/
        return new PdaResult();
    }

    /**
     * 获取指定调拨单的调拨出库任务
     * @param id 调拨主表主键
     * @return PdaResult 详情列表
     */
    @Override
    public PdaResult alloOutSelectDetailById(Long id) {
        return new PdaResult(pdaDAO.alloOutSelectDetailById(id));
    }

    /**
     * 获取调拨入库任务
     * @param id 主表主键
     * @return PdaResult 详情列表
     */
    @Override
    public PdaResult alloInSelectDetailById(Long id) {
        return new PdaResult(pdaDAO.alloInSelectDetailById(id));
    }

    /**
     * 删除主表信息，子表信息  需要判断该主表下有无已经开始的字表信息，如有则提示  库存表更改状态
     * @param id 主表主键
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult alloDelInfoAndDetail(Long id) {
        if (pdaDAO.selectDetailsState(id) > 0){
            return new PdaResult(1, "该调拨单下已经有数据进行出入库操作,请勿删除!", "");
        }

        allocationDetailDAO.selectByMap(new HashMap<String, Object>(1) {{
            put("PID", id);
        }}).forEach(allocationDetail -> {
            StorageInfo storageInfo = storageInfoDAO.selectOne(new StorageInfo() {{
                setBatchNo(allocationDetail.getBatchNo());
            }});
            storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
            storageInfoDAO.updateById(storageInfo);
        });

        allocationDAO.deleteById(id);
        allocationDetailDAO.deleteByMap(new HashMap<String, Object>() {{
            put("PID", id);
        }});
        return new PdaResult();
    }

    /**
     * 删除子表信息  判断该字表的状态  更改库存表的状态
     * @param id 主表id
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult alloDelDetail(Long id) {
        AllocationDetail allocationDetail = allocationDetailDAO.selectById(id);
        StorageInfo storageInfo = storageInfoDAO.selectOne(new StorageInfo() {{
            setRfid(allocationDetail.getRfid());
        }});
        storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
        storageInfoDAO.updateById(storageInfo);
        allocationDetailDAO.deleteById(allocationDetail.getId());
        return new PdaResult();
    }

    /**
     * 扫描，开始出库  将状态改为开始出库
     * 状态 1:未开始 2.开始调拨出库 3.完成调拨出库 4.开始调拨入库 5.完成调拨入库
     * @param rfid rfid
     * @param carCode 行车编码
     * @param barcode 二维码信息
     * @param barcodeType 扫码类型
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult alloOutStorageStart(String rfid, String carCode, String barcode, String barcodeType) {
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("barcode", barcode);
        queryMap.put("barcodeType", barcodeType);
        queryMap.put("rfid", rfid);
        queryMap.put("stateList", Arrays.stream("1".split(",")).map(Long::parseLong).collect(Collectors.toList()));
        AllocationDetail allocationDetail = pdaDAO.findAllocationDetailByqbr(queryMap).get(0);
        allocationDetail.setCarCode(carCode);
        allocationDetail.setOutCarCode(carCode);
        allocationDetail.setState(EmumConstant.locationChangeStatus.START_CHANGE_OUT.getCode());
        allocationDetail.setStartOutStorageTime(new Date());
        allocationDetailDAO.updateById(allocationDetail);
        //行车状态更新
        carDAO.updateCarByCode(carCode, allocationDetail.getOutShelfCode(), Long.valueOf(EmumConstant.carState.OUTSTORAGING.getCode()));

        return new PdaResult();
    }

    /**
     * 点击，完成出库
     * @param rfid rfid
     * @param userId 用户主键
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult alloOutStorageSuccess(String rfid, Long userId) {
        List<StorageInfo> lstStorageInfo = storageInfoDAO.selectByMap(new HashMap<String, Object>(1) {{
            put("RFID", rfid);
        }});
        if (lstStorageInfo == null || lstStorageInfo.size() != 1) {
            return new PdaResult(1, "库存数据异常,请联系管理员查看!", "");
        }
        StorageInfo storageInfo = lstStorageInfo.get(0);

        List<AllocationDetail> lstAllocationDetail = allocationDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
            put("state", EmumConstant.locationChangeStatus.START_CHANGE_OUT.getCode());
        }});
        AllocationDetail allocationDetail = lstAllocationDetail.get(0);
        Allocation allocation = allocationDAO.selectById(allocationDetail.getPId());

        AlloOutStorage alloOutStorage = new AlloOutStorage();
        alloOutStorage.setOrg(allocationDetail.getOrg());
        alloOutStorage.setBatchNo(allocationDetail.getBatchNo());
        alloOutStorage.setMaterialCode(allocationDetail.getMaterialCode());
        alloOutStorage.setQaCode(allocationDetail.getQaCode());
        alloOutStorage.setSalesCode(allocationDetail.getSalesCode());
        alloOutStorage.setSalesName(allocationDetail.getSalesName());
        alloOutStorage.setRfid(allocationDetail.getRfid());
        alloOutStorage.setMeter(allocationDetail.getMeter());
        alloOutStorage.setCarCode(allocationDetail.getOutCarCode());
        List<Car> lstCar = carDAO.selectByMap(new HashMap<String, Object>(){{
            put("CODE", allocationDetail.getOutCarCode());
        }});
        if (lstCar.size()>0){
            alloOutStorage.setOutcarerid(lstCar.get(0).getLoginer());
        }
        alloOutStorage.setShelfCode(allocationDetail.getOutShelfCode());
        alloOutStorage.setWarehouseCode(allocation.getOutWarehouseCode());
        alloOutStorage.setStartStorageTime(allocationDetail.getStartOutStorageTime());
        alloOutStorage.setOutstoragetime(new Date());
        alloOutStorage.setOutStorageId(userId);
        alloOutStorage.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        alloOutStorage.setDishnumber(allocationDetail.getDishnumber());
        alloOutStorageDAO.insert(alloOutStorage);
        //更新库存状态库存
        storageInfo.setState(EmumConstant.storageInfoState.LOCKING.getCode());
        storageInfoDAO.updateById(storageInfo);

        allocationDetail.setState(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_OUT.getCode());
        allocationDetail.setOutStorageTime(new Date());
        allocationDetail.setOutStorageId(userId);
        allocationDetailDAO.updateById(allocationDetail);
        //更新行车状态
        carDAO.updateCarByCode(allocationDetail.getOutCarCode(),"",Long.valueOf(EmumConstant.carState.UNUSED.getCode()));
        //库位可用
        shelfImpl.setShelfState(allocationDetail.getOutShelfCode(),allocation.getFactoryCode(),allocationDetail.getOutWarehouseCode(),1);

        return new PdaResult();
    }

    /**
     * 显示所有待入库的调拨单
     * @param userId 用户ID
     * @return List<Allocation>
     */
    @Override
    public PdaResult pendingAlloStorageList(Long userId) {
         return new PdaResult(pdaDAO.pendingAlloStorageList(Arrays.asList(userDAO.selectById(userId).getFactoryCode().split(","))));
    }

    /**
     * 扫描rfid,跳转到调拨入库界面
     * @param rfid rfid
     * @param barcode 二维码信息
     * @param barcodeType 二维码类型
     * @param carCode 行车编码
     * @return PdaResult
     */
    @Override
    public PdaResult alloInStorageList(String rfid, String barcode, String barcodeType, String carCode) {
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("barcode", barcode);
        queryMap.put("barcodeType", barcodeType);
        queryMap.put("rfid", rfid);
        queryMap.put("stateList",Arrays.stream("3,4".split(",")).map(Long::parseLong).collect(Collectors.toList()));
        AllocationDetail allocationDetail = pdaDAO.findAllocationDetailByqbr(queryMap).get(0);
        InstorageDetail instorageDetail = instorageDetailDAO.selectOne(new InstorageDetail(){{
            setQaCode(allocationDetail.getQaCode());
        }});

        Allocation allocation = allocationDAO.selectById(allocationDetail.getPId());
        Warehouse warehouse = warehouseDAO.selectByMap(new HashMap<String,Object>(){{
            put("CODE",allocation.getInWarehouseCode());
            put("FACTORYCODE",allocation.getInFactoryCode());
        }}).get(0);

        Car car = null;
        if (StringUtils.isNotBlank(carCode)){
            car = carDAO.selectOne(new Car() {{
                setCode(carCode);
            }});
        }

        //获取推荐库位
        List<Shelf> recommendList = shelfImpl.selectRecommentList(allocation.getInFactoryCode(), allocation.getInWarehouseCode(),
                allocationDetail.getOuterDiameter() != null ? allocationDetail.getOuterDiameter().toString() : "",
                allocationDetail.getDrumType(), carCode, "", car != null ? car.getWarehouseArea() : "",
                allocationDetail.getSalesCode(), allocationDetail.getSuperWide(), "黑色".equals(instorageDetail.getColour()) ||
                        StringUtils.isBlank(instorageDetail.getColour()) ? 0 : 1);
        if(recommendList==null||recommendList.size()==0) {
            recommendList = new ArrayList<>();
            List<Shelf> useShelfList = shelfDAO.getRecommendShelf(allocation.getInWarehouseCode(), allocation.getInFactoryCode(),
                    car != null && StringUtils.isNotBlank(car.getWarehouseArea()) ? Arrays.asList(car.getWarehouseArea().split(",")) :
                    new ArrayList<>());
            if (useShelfList!=null && useShelfList.size()>0) {
                recommendList.add(useShelfList.get(0));
            }
        }

        allocationDetail.setInCarCode(carCode);
        allocationDetail.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        allocationDetail.setStartInStorageTime(new Date());
        allocationDetailDAO.updateById(allocationDetail);
        //更新行车状态
        carDAO.updateCarByCode(carCode, recommendList.size() > 0 ? recommendList.get(0).getCode() : "",
                Long.valueOf(EmumConstant.carState.INSTORAGING.getCode()));

        //记录推荐库位
        ShipLoadingDetail shipLoadingDetail = new ShipLoadingDetail();
        shipLoadingDetail.setCreateTime(new Date());
        shipLoadingDetail.setMaterialCode(recommendList.size() > 0 ? recommendList.get(0).getCode() : "");
        shipLoadingDetail.setQaCode(instorageDetail.getQaCode());
        shipLoadingDetail.setPId(9999L);
        shipLoadingDetail.setShipNo("调拨入库");
        shipLoadingDetailDAO.insert(shipLoadingDetail);

        Map<String, Object> map = new HashMap<>();
        map.put("detail", allocationDetail);
        map.put("warehouseIn", warehouse);
        map.put("shelveList", recommendList);
        return new PdaResult(map);
    }

    /**
     * 点击开始，修改状态为开始调拨入库
     * @param rfid rfid
     * @param shelfCode 库位编码
     * @param carCode 行车编码
     * @param warehouseCode 仓库编码
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult alloInStorageStart(String rfid, String shelfCode, String carCode, String warehouseCode) {
        List<AllocationDetail> lstAllocationDetail = allocationDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
            put("state", EmumConstant.locationChangeStatus.COMPLETE_CHANGE_OUT.getCode());
        }});

        AllocationDetail allocationDetail = lstAllocationDetail.get(0);
        allocationDetail.setInCarCode(carCode);
        allocationDetail.setInShelfCode(shelfCode);
        allocationDetail.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        allocationDetail.setStartInStorageTime(new Date());
        allocationDetailDAO.updateById(allocationDetail);
        //更新行车状态
        carDAO.updateCarByCode(carCode, shelfCode, Long.valueOf(EmumConstant.carState.INSTORAGING.getCode()));

        return new PdaResult();
    }

    /**
     * 完成入库,状态改为调拨入库完成
     * @param rfid rfid
     * @param userId 用户主键
     * @param shelfCode 最终库位
     * @return PdaResult
     */
    @Override
    public PdaResult alloInStorageSuccess(String rfid, Long userId, String shelfCode) {
        AllocationDetail allocationDetail = allocationDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
            put("state", EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        }}).get(0);
        //判断移入的库位是否与移出库位相同，如果相同提示
        if(shelfCode.equals(allocationDetail.getOutShelfCode())){
            new PdaResult(1, "该盘货已经在"+shelfCode+"库位，无需变更！", "");
        }
        allocationDetail.setTargetShelf(shelfCode);
        allocationDetailDAO.updateById(allocationDetail);
        return alloInStorageSuccessFinish(rfid, userId, shelfCode);
    }

    /**
     * 完成入库,状态改为调拨入库完成
     * @param rfid rfid
     * @param userId 用户主键
     * @param shelfCode 最终库位
     * @return PdaResult
     */
    @Transactional(rollbackFor = Exception.class)
    public PdaResult alloInStorageSuccessFinish(String rfid, Long userId, String shelfCode) {
        AllocationDetail allocationDetail = allocationDetailDAO.selectByMap(new HashMap<String, Object>(2) {{
            put("RFID", rfid);
            put("state", EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        }}).get(0);
        Allocation allocation = allocationDAO.selectById(allocationDetail.getPId());

        Map<String,Object> mapVMaterial = pdaDAO.findOrgByVmaterial(new HashMap<String,Object>(){{
            put("qacode", allocationDetail.getQaCode());
        }});
        //调EBS调拨接口
        Map<String,Object> xmlMap = new HashMap<>(1);
        xmlMap.put("line",new HashMap<String,Object>(5){{
            put("org", mapVMaterial.get("ORG"));
            put("batchno",allocationDetail.getBatchNo());
            put("qacode", allocationDetail.getQaCode());
            //新仓库
            put("inwarehouse",allocationDetail.getInWarehouseCode());
            //新最终库位
            put("inLocation",shelfDAO.selectOne(new Shelf(){{
                setCode(shelfCode);
            }}).getCodeComplete());
        }});
        logger.info("FEWMS008存入接口待执行表！");
        while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS008 + allocationDetail.getQaCode() + "PDA")){
            try {
                TimeUnit.MILLISECONDS.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //把接口编码+质保号放到内存中
        ConRunningMap.addItem(EbsInterfaceEnum.FEWMS008 + allocationDetail.getQaCode() + "PDA");
        interfaceDoServiceImpl.insertDo(EbsInterfaceEnum.FEWMS008, "EBS接口-调拨、移库接口", JSONObject.toJSONString(xmlMap),
                DateUtils.getTime(), allocationDetail.getQaCode(),allocationDetail.getBatchNo(),null,allocation.getAllCode());
        ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS008 + allocationDetail.getQaCode() + "PDA");

        allocationDetail.setState(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_IN.getCode());
        allocationDetail.setInStorageTime(new Date());
        allocationDetail.setInStorageId(userId);
        allocationDetail.setOrg(allocation.getInFactoryCode());
        //最终库位
        allocationDetail.setInShelfCode(shelfCode);
        allocationDetailDAO.updateById(allocationDetail);

        AlloInStorage alloInStorage = new AlloInStorage();
        alloInStorage.setOrg(allocation.getInFactoryCode());
        alloInStorage.setMaterialCode(allocationDetail.getMaterialCode());
        alloInStorage.setBatchNo(allocationDetail.getBatchNo());
        alloInStorage.setQaCode(allocationDetail.getQaCode());
        alloInStorage.setSalesCode(allocationDetail.getSalesCode());
        alloInStorage.setSalesName(allocationDetail.getSalesName());
        alloInStorage.setRfid(allocationDetail.getRfid());
        alloInStorage.setMeter(allocationDetail.getMeter());
        alloInStorage.setShelfCode(shelfCode);
        alloInStorage.setCarCode(allocationDetail.getInCarCode());
        List<Car> lstCar = carDAO.selectByMap(new HashMap<String, Object>(){{
            put("CODE", allocationDetail.getInCarCode());
        }});
        if (lstCar.size()>0){
            alloInStorage.setIncarerid(lstCar.get(0).getLoginer());
        }
        alloInStorage.setWarehouseCode(allocationDetail.getInWarehouseCode());
        alloInStorage.setStartStorageTime(allocationDetail.getStartInStorageTime());
        alloInStorage.setInstorageTime(new Date());
        alloInStorage.setEntityNo(allocationDetail.getEntityNo());
        alloInStorage.setDishnumber(allocationDetail.getDishnumber());
        alloInStorageDAO.insert(alloInStorage);

        StorageInfo storageInfo = storageInfoDAO.selectOne(new StorageInfo(){{
            setRfid(rfid);
        }});
        storageInfo.setShelfCode(shelfCode);
        storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
        storageInfoDAO.updateById(storageInfo);

        //恢复行车状态为可用
        carDAO.updateCarByCode(allocationDetail.getInCarCode(),"",Long.valueOf(EmumConstant.carState.UNUSED.getCode()));
        //库位不可用
        shelfImpl.setShelfState(shelfCode,allocation.getInFactoryCode(),allocationDetail.getInWarehouseCode(),0);

        return new PdaResult();
    }

    /**
     * 点击加号后的扫描物料，手持机端的扫码都是获取的质保号
     * @param rfid rfid
     * @param userId 用户主键
     * @param barcode 二维码
     * @param barcodeType 二维码类型
     * @return PdaResult 库存列表
     */
    @Override
    public PdaResult moveStorageInfoList(String rfid, Long userId, String barcode, String barcodeType) {
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("barcode", barcode);
        queryMap.put("barcodeType", barcodeType);
        queryMap.put("rfid", rfid);
        StorageInfo storageInfo = pdaDAO.findStorageInfoByqbr(queryMap);
        if (storageInfo == null) {
            Split split = splitDAO.findSplitByqbr(queryMap);
            if (split == null){
                return new PdaResult(1, "库存中没有该线盘信息,无法生成移库任务", "");
            }else {
                storageInfo = new StorageInfo();
                storageInfo.setMaterialCode(split.getMaterialCode());
                storageInfo.setBatchNo(split.getBatchNo());
                storageInfo.setQaCode(split.getQaCode());
                storageInfo.setShelfCode(split.getShelfCode());
                storageInfo.setWarehouseCode(split.getWarehouseCode());
                storageInfo.setMeter(split.getMeter());
                storageInfo.setRfid(split.getRfid());
                storageInfo.setOrg(split.getOrg());
                storageInfo.setSalesCode(split.getSalesCode());
                storageInfo.setSalesName(split.getSalesName());
                storageInfo.setInStorageId(split.getSplitStorageId());
                storageInfo.setState(split.getState());
                storageInfo.setEntityNo(split.getEntityNo());
                storageInfo.setOrderno(split.getOrderno());
                storageInfo.setOrderline(split.getOrderline());
                storageInfo.setDishnumber(split.getDishnumber());
                storageInfo.setInStorageTime(split.getSplitTime());
            }
        }

        List<AllocationDetail> lstAllocationDetail = allocationDetailDAO.selectList(new EntityWrapper<AllocationDetail>()
                .eq("RFID",storageInfo.getQaCode())
                .in("STATE","1,2,3,4"));
        //该物料存在于移库单中，且还未完成
        return lstAllocationDetail.size() > 0 ? new PdaResult(1, "该货物处在其他移库任务中，请先完成再添加", "") :
                new PdaResult(storageInfo);
    }

    /**
     * 点击提交，生成移库单
     * @param map storageInfoRfids（库存主键）,userId(用户主键)，org(厂区编码)
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult moveAdd(Map<String, Object> map) {
        if (map == null || map.get("userId") == null || map.get("storageInfoRfids") == null) {
            return new PdaResult(1, "输入参数异常,请检查！", "");
        }

        //主界面扫描进入提交界面后所选的行车，如果是添加按钮进入的扫描界面，则不传carCode
        String carCode = (String) map.get("carCode");
        //区分主界面扫描或加号扫描的标志：1主界面扫描；0加号扫描
        Integer scanSign = map.get("carCode") == null ? EmumConstant.mainInterfaceScanning.NO.getCode() :
                EmumConstant.mainInterfaceScanning.YES.getCode();
        //物料明细rfid
        @SuppressWarnings("unchecked")
        List<String> lstRfid = (List<String>) map.get("storageInfoRfids");
        //随便取一个库存，这里只是为了获取这一批数据的公共信息
        StorageInfo storageIn = storageInfoDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", lstRfid.get(0));
        }}).get(0);

        Allocation allocation = new Allocation();
        String serial = new DecimalFormat("0000").format( moveStorageDAO.selectLatestAllocation() + 1);
        Long warehouseId = warehouseDAO.selectList(new EntityWrapper<Warehouse>()
                .eq("CODE", storageIn.getWarehouseCode())
                .eq("FACTORYCODE", storageIn.getOrg())).get(0).getId();

        allocation.setAllCode("YK" + DateUtils.getDays() + serial);
        allocation.setMoveTime(new Date());
        allocation.setInWarehouseCode(storageIn.getWarehouseCode());
        allocation.setOutWarehouseCode(storageIn.getWarehouseCode());
        allocation.setInWarehouseId(warehouseId);
        allocation.setOutWarehouseId(warehouseId);
        allocation.setFactoryCode(storageIn.getOrg());
        allocation.setInFactoryCode(storageIn.getOrg());
        allocation.setUserId(Long.valueOf((String)map.get("userId")));
        allocation.setState(scanSign);
        allocationDAO.insert(allocation);
        //更新移库单流水号
        moveStorageDAO.updateSerial(serial,"move");

        lstRfid.forEach(rfid -> {
            StorageInfo storageInfo = storageInfoDAO.selectOne(new StorageInfo() {{
                setRfid(rfid);
            }});
            storageInfo.setState(EmumConstant.storageInfoState.LOCKING.getCode());
            storageInfoDAO.updateById(storageInfo);

            AllocationDetail allocationDetail = new AllocationDetail();
            allocationDetail.setMaterialCode(storageInfo.getMaterialCode());
            allocationDetail.setMeter(storageInfo.getMeter());
            allocationDetail.setRfid(storageInfo.getRfid());
            allocationDetail.setQaCode(storageInfo.getQaCode());
            allocationDetail.setPId(allocation.getId());
            allocationDetail.setBatchNo(storageInfo.getBatchNo());
            allocationDetail.setInWarehouseCode(storageInfo.getWarehouseCode());
            allocationDetail.setOrg(storageInfo.getOrg());
            allocationDetail.setOutWarehouseCode(storageInfo.getWarehouseCode());
            allocationDetail.setOutShelfCode(storageInfo.getShelfCode());
            allocationDetail.setOutCarCode(carCode);
            allocationDetail.setSalesCode(storageInfo.getSalesCode());
            allocationDetail.setSalesName(storageInfo.getSalesName());
            allocationDetail.setWarehouseCode(storageInfo.getWarehouseCode());
            allocationDetail.setEntityNo(storageInfo.getEntityNo());
            allocationDetail.setDishnumber(storageInfo.getDishnumber());
            allocationDetailDAO.insert(allocationDetail);

            //如果是主界面扫描，点击提交时，直接默认移库出库完成
            if(EmumConstant.mainInterfaceScanning.YES.getCode().equals(scanSign)){
                moveOutStorageSuccess(storageInfo.getRfid(), Long.valueOf((String) map.get("userId")));
            }
        });

        return new PdaResult();
    }

    /**
     * 返回所有未完成的主表信息
     * @param userId 用户主键
     * @return PdaResult 移库单主表列表
     */
    @Override
    public PdaResult moveSelectAllUndo(Long userId) {
        return new PdaResult(pdaDAO.selectAllMoveStorage(Arrays.asList(userDAO.selectById(userId).getFactoryCode().split(","))));
    }

    /**
     * 返回所有未完成移库出库的主表信息
     * @param userId 用户主键
     * @return PdaResult 移库单主表列表
     */
    @Override
    public PdaResult moveSelectPartUndo(Long userId) {
        return new PdaResult(pdaDAO.moveSelectPartUndo(Arrays.asList(userDAO.selectById(userId).getFactoryCode().split(","))));
    }

    /**
     * 移库功能模块进入，展示移库单明细列表
     * @param id 移库主表主键
     * @return PdaResult 详情列表
     */
    @Override
    public PdaResult moveSelectDetailById(Long id) {
        return new PdaResult(pdaDAO.moveSelectDetailById(id));
    }

    /**
     * 移库出库，进入移库出库单展示列表后，将任务同步行车
     * @param id 主表id
     * @param carCode 行车编码
     * @return PdaResult 详情列表
     */
    @Override
    public PdaResult moveMissionToCar(Long id,String carCode) {
        /*String shelfCodes = "";
        Car car = carDAO.selectOne(new Car() {{
            setCode(carCode);
        }});

        List<MoveStorageDetail> lstMoveStorageDetail = moveStorageDetailDAO.selectList(new EntityWrapper<MoveStorageDetail>()
                .eq("PID", id).in("STATE", "1,2")
                .addFilter("OUTSHELFCODE LIKE {0}", car.getWarehouseArea()+"%"));

        if (lstMoveStorageDetail!=null){
            for (MoveStorageDetail moveStorageDetail : lstMoveStorageDetail) {
                shelfCodes += moveStorageDetail.getOutShelfCode() + ",";
            }
        }

        car.setMission(shelfCodes);
        carDAO.updateById(car);*/
        return new PdaResult();
    }

    /**
     * 移库入库展示明细
     * @param id 移库主表主键
     * @return PdaResult 详情列表
     */
    @Override
    public PdaResult moveInSelectDetailById(Long id) {
        return new PdaResult(pdaDAO.moveInSelectDetailById(id));
    }

    /**
     * 移库出库展示明细
     * @param id 移库主表主键
     * @return PdaResult 详情列表
     */
    @Override
    public PdaResult moveOutSelectDetailById(Long id) {
        return new PdaResult(pdaDAO.moveOutSelectDetailById(id));
    }

    /**
     * 删除主表信息，子表信息  需要判断该主表下有无已经开始的子表信息，如有则提示  更新库存状态
     * @param id 主表id
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult moveDelInfoAndDetail(Long id) {
        if (pdaDAO.selectDetailsStateMove(id) > 0){
            return new PdaResult(1, "该移库单下已经有数据进行出入库操作,请勿删除!", "");
        }

        allocationDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("PID", id);
        }}).forEach(allocationDetail -> {
            StorageInfo storageInfo = storageInfoDAO.selectOne(new StorageInfo() {{
                setBatchNo(allocationDetail.getBatchNo());
            }});
            storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
            storageInfoDAO.updateById(storageInfo);
        });

        allocationDAO.deleteById(id);
        allocationDetailDAO.deleteByMap(new HashMap<String, Object>(1) {{
            put("PID", id);
        }});
        return new PdaResult();
    }

    /**
     * 删除明细信息  判断该字表的状态
     * @param id 移库明细表主键
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult moveDelDetail(Long id) {
        AllocationDetail allocationDetail = allocationDetailDAO.selectById(id);

        List<StorageInfo> lstStorageInfo = storageInfoDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", allocationDetail.getRfid());
        }});
        if (lstStorageInfo != null && lstStorageInfo.size() == 1) {
            StorageInfo storageInfo = lstStorageInfo.get(0);
            storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
            storageInfoDAO.updateById(storageInfo);
        }

        moveStorageDetailDAO.deleteById(allocationDetail.getId());
        return new PdaResult();
    }

    /**
     * 扫描，开始出库  将状态改为开始出库,并把库位任务推送给对应航车
     * 状态 1:未开始 2.开始移库出库 3.完成移库出库 4.开始移库入库 5.完成移库入库
     * @param rfid rfid
     * @param carCode 行车编码
     * @param barcode 二维码信息
     * @param barcodeType 二维码类型
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult moveOutStorageStart(String rfid, String carCode, String barcode,String barcodeType) {
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("barcode", barcode);
        queryMap.put("barcodeType", barcodeType);
        queryMap.put("rfid", rfid);
        queryMap.put("stateList",Arrays.stream("1,2".split(",")).map(Long::parseLong).collect(Collectors.toList()));
        AllocationDetail allocationDetail = pdaDAO.findAllocationDetailByqbr(queryMap).get(0);
        allocationDetail.setCarCode(carCode);
        allocationDetail.setOutCarCode(carCode);
        allocationDetail.setState(EmumConstant.locationChangeStatus.START_CHANGE_OUT.getCode());
        allocationDetail.setStartOutStorageTime(new Date());
        allocationDetailDAO.updateById(allocationDetail);
        //更新行车使用状态及行车推荐库位任务
        carDAO.updateCarByCode(carCode,allocationDetail.getOutShelfCode(),Long.valueOf(EmumConstant.carState.OUTSTORAGING.getCode()));

        return new PdaResult();
    }

    /**
     * 点击，完成出库
     * @param rfid rfid
     * @param userId 用户主键
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult moveOutStorageSuccess(String rfid, Long userId) {
        List<StorageInfo> storageInfos = storageInfoDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
        }});
        if (storageInfos.size() == 0) {
            List<Split> lstSplit = splitDAO.selectList(new EntityWrapper<Split>().eq("RFID", rfid));
            if (lstSplit.size() == 0){
                return new PdaResult(1, "库存中已无此货物!", "");
            }else {
                Split split = lstSplit.get(0);
                //更新库存状态为出库中
                split.setState(EmumConstant.storageInfoState.LOCKING.getCode());
                splitDAO.updateById(split);
            }
        }else {
            StorageInfo storageInfo = storageInfos.get(0);
            //更新库存状态为出库中
            storageInfo.setState(EmumConstant.storageInfoState.LOCKING.getCode());
            storageInfoDAO.updateById(storageInfo);
        }

        AllocationDetail allocationDetail = allocationDetailDAO.selectList(new EntityWrapper<AllocationDetail>()
                .eq("RFID",rfid)
                .ne("STATE",EmumConstant.locationChangeStatus.COMPLETE_CHANGE_IN.getCode())).get(0);

        allocationDetail.setState(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_OUT.getCode());
        allocationDetail.setOutStorageTime(new Date());
        allocationDetail.setOutStorageId(userId);
        allocationDetailDAO.updateById(allocationDetail);

        MoveOutStorage moveOutStorage = new MoveOutStorage();
        moveOutStorage.setOrg(allocationDetail.getOrg());
        moveOutStorage.setMaterialCode(allocationDetail.getMaterialCode());
        moveOutStorage.setBatchNo(allocationDetail.getBatchNo());
        moveOutStorage.setQaCode(allocationDetail.getQaCode());
        moveOutStorage.setSalesCode(allocationDetail.getSalesCode());
        moveOutStorage.setSalesName(allocationDetail.getSalesName());
        moveOutStorage.setRfid(allocationDetail.getRfid());
        moveOutStorage.setMeter(allocationDetail.getMeter());
        moveOutStorage.setShelfCode(allocationDetail.getOutShelfCode());
        moveOutStorage.setWarehouseCode(allocationDetail.getWarehouseCode());
        moveOutStorage.setCarCode(allocationDetail.getOutCarCode());
        List<Car> lstCar = carDAO.selectByMap(new HashMap<String, Object>(){{
            put("CODE", allocationDetail.getOutCarCode());
        }});
        if (lstCar.size()>0){
            moveOutStorage.setOutcarerid(lstCar.get(0).getLoginer());
        }
        moveOutStorage.setStartStorageTime(allocationDetail.getStartOutStorageTime());
        moveOutStorage.setOutStorageTime(allocationDetail.getOutStorageTime());
        moveOutStorage.setOutStorageId(allocationDetail.getOutStorageId());
        moveOutStorage.setDishnumber(allocationDetail.getDishnumber());
        moveOutStorageDAO.insert(moveOutStorage);

        //更新行车任务和状态
        carDAO.updateCarByCode(allocationDetail.getOutCarCode(),"",Long.valueOf(EmumConstant.carState.UNUSED.getCode()));
        //库位可用
        shelfImpl.setShelfState(allocationDetail.getOutShelfCode(),allocationDetail.getOrg(),allocationDetail.getOutWarehouseCode(),1);

        return new PdaResult();
    }

    /**
     * 显示所有待入库的移库单
     * @param userId 用户主键
     * @return List<MoveStorage>
     */
    @Override
    public PdaResult pendingMoveStorageList(Long userId) {
         return new PdaResult(pdaDAO.pendingMoveStorageList(Arrays.asList(userDAO.selectById(userId).getFactoryCode().split(","))));
    }

    /**
     * 扫描，跳转到移库入库界面
     * @param rfid rfid
     * @param barcode 二维码信息
     * @param barcodeType 二维码扫码类型
     * @param carCode 行车编码
     * @return PdaResult
     */
    @Override
    public PdaResult moveInStorageList(String rfid,String barcode,String barcodeType,String carCode) {
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("barcode", barcode);
        queryMap.put("barcodeType", barcodeType);
        queryMap.put("rfid", rfid);
        queryMap.put("stateList",Arrays.stream("3,4".split(",")).map(Long::parseLong).collect(Collectors.toList()));
        AllocationDetail allocationDetail = pdaDAO.findAllocationDetailByqbr(queryMap).get(0);
        InstorageDetail instorageDetail = instorageDetailDAO.selectOne(new InstorageDetail(){{
            setQaCode(allocationDetail.getQaCode());
        }});

        Car car = null;
        if (StringUtils.isNotBlank(carCode)){
            car = carDAO.selectOne(new Car() {{
                setCode(carCode);
            }});
        }
        Warehouse warehouse = warehouseDAO.selectById(allocationDAO.selectById(allocationDetail.getPId()).getInWarehouseId());
        List<Shelf> recommendList = shelfImpl.selectRecommentList(warehouse.getFactoryCode(),warehouse.getCode(),
                allocationDetail.getOuterDiameter() !=null ? allocationDetail.getOuterDiameter().toString() : "",
                allocationDetail.getDrumType(), carCode, allocationDetail.getOutShelfCode(), car!=null ?
                car.getWarehouseArea() : "", allocationDetail.getSalesCode(), allocationDetail.getSuperWide(),
                "黑色".equals(instorageDetail.getColour()) || StringUtils.isBlank(instorageDetail.getColour()) ? 0 : 1);
        if(recommendList==null || recommendList.size()==0) {
            recommendList = new ArrayList<>();
            List<Shelf> useShelfList = shelfDAO.getRecommendShelf(warehouse.getCode(), warehouse.getFactoryCode(),
                    car != null && StringUtils.isNotBlank(car.getWarehouseArea()) ? Arrays.asList(car.getWarehouseArea().split(",")) :
                    new ArrayList<>());
            List<Shelf> list = useShelfList.stream().filter(s -> !allocationDetail.getOutShelfCode().equals(s.getCode()))
                    .collect(Collectors.toList());
            recommendList.add(list.size() > 0 ? list.get(0) : new Shelf());
        }

        allocationDetail.setInCarCode(carCode);
        allocationDetail.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        allocationDetail.setStartInStorageTime(new Date());
        allocationDetailDAO.updateById(allocationDetail);

        //设置行车状态为不可用
        carDAO.updateCarByCode(carCode, recommendList.size()>0 ? recommendList.get(0).getCode() : "",
                Long.valueOf(EmumConstant.carState.INSTORAGING.getCode()));

        //记录推荐库位
        ShipLoadingDetail shipLoadingDetail = new ShipLoadingDetail();
        shipLoadingDetail.setCreateTime(new Date());
        shipLoadingDetail.setMaterialCode(recommendList.size() > 0 ? recommendList.get(0).getCode() : "");
        shipLoadingDetail.setQaCode(instorageDetail.getQaCode());
        shipLoadingDetail.setPId(9999L);
        shipLoadingDetail.setShipNo("移库入库");
        shipLoadingDetailDAO.insert(shipLoadingDetail);

        Map<String, Object> map = new HashMap<>();
        map.put("detail",allocationDetail);
        map.put("warehouseIn",warehouse);
        map.put("shelveList",recommendList);
        return new PdaResult(map);
    }

    /**
     * 点击开始，修改状态为开始移库入库
     * @param rfid rfid
     * @param shelfCode 库位编码
     * @param carCode 行车
     * @param warehouseCode 仓库编码
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult moveInStorageStart(String rfid, String shelfCode, String carCode, String warehouseCode) {
        MoveStorageDetail moveStorageDetail = moveStorageDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
            put("STATE", EmumConstant.locationChangeStatus.COMPLETE_CHANGE_OUT.getCode());
        }}).get(0);
        moveStorageDetail.setInCarCode(carCode);
        moveStorageDetail.setInShelfCode(shelfCode);
        moveStorageDetail.setWarehouseCode(warehouseCode);
        moveStorageDetail.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        moveStorageDetail.setStartInStorageTime(new Date());
        moveStorageDetailDAO.updateById(moveStorageDetail);
        //设置行车状态为不可用
        carDAO.updateCarByCode(carCode, shelfCode, Long.valueOf(EmumConstant.carState.INSTORAGING.getCode()));
        return new PdaResult();
    }

    /**
     * 结束,状态改为完成移库入库
     * @param rfid rfid
     * @param userId 用户主键
     * @param shelfCode 最终库位
     * @return PdaResult
     */
    @Override
    public PdaResult moveInStorageSuccess(String rfid, Long userId, String shelfCode) {
        if(StringUtils.isBlank(shelfCode)){
            new PdaResult(1, "请选择移入的库位！", "");
        }
        AllocationDetail allocationDetail = allocationDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
            put("state", EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        }}).get(0);
        //判断移入的库位是否与移出库位相同，如果相同提示
        if(shelfCode.equals(allocationDetail.getOutShelfCode())){
            new PdaResult(1, "移入的库位不能与移出库位相同，请重新选择库位！", "");
        }
        allocationDetail.setTargetShelf(shelfCode);
        allocationDetailDAO.updateById(allocationDetail);
        return moveInStorageSuccessFinish(rfid, userId, shelfCode);
    }

    /**
     * 结束,状态改为完成移库入库
     * @param rfid rfid
     * @param userId 用户主键
     * @param shelfCode 最终库位
     * @return PdaResult
     */
    @Transactional(rollbackFor = Exception.class)
    public PdaResult moveInStorageSuccessFinish(String rfid, Long userId, String shelfCode) {
        AllocationDetail allocationDetail = allocationDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
            put("state", EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
        }}).get(0);

        Allocation allocation = allocationDAO.selectById(allocationDetail.getPId());
        InstorageDetail instorageDetail = instorageDetailDAO.selectByMap(new HashMap<String, Object>() {{
            put("RFID", rfid);
        }}).get(0);
        //调EBS移库接口
        Map<String,Object> xmlMap = new HashMap<>();
        xmlMap.put("line",new HashMap<String,Object>(){{
            put("org",instorageDetail.getOrg());
            put("batchno",allocationDetail.getBatchNo());
            put("qacode",allocationDetail.getQaCode());
            //新仓库
            put("inwarehouse",allocationDetail.getInWarehouseCode());
            //最终库位
            put("inLocation",shelfDAO.selectOne(new Shelf(){{
                setCode(shelfCode);
            }}).getCodeComplete());
        }});
        logger.info("FEWMS008存入接口待执行表！");
        while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS008 + allocationDetail.getQaCode() + "PDA")){
            try {
                TimeUnit.MILLISECONDS.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //把接口编码+质保号放到内存中
        ConRunningMap.addItem(EbsInterfaceEnum.FEWMS008 + allocationDetail.getQaCode() + "PDA");
        interfaceDoServiceImpl.insertDo(EbsInterfaceEnum.FEWMS008, "EBS接口-调拨、移库接口", JSONObject.toJSONString(xmlMap),
                DateUtils.getTime(), allocationDetail.getQaCode(),allocationDetail.getBatchNo(),null, allocation.getAllCode());
        ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS008 + allocationDetail.getQaCode() + "PDA");

        allocationDetail.setState(EmumConstant.locationChangeStatus.COMPLETE_CHANGE_IN.getCode());
        allocationDetail.setInStorageTime(new Date());
        allocationDetail.setInStorageId(userId);
        allocationDetail.setInShelfCode(shelfCode);
        allocationDetailDAO.updateById(allocationDetail);

        MoveInStorage moveInStorage = new MoveInStorage();
        moveInStorage.setOrg(allocationDetail.getOrg());
        moveInStorage.setMaterialCode(allocationDetail.getMaterialCode());
        moveInStorage.setBatchNo(allocationDetail.getBatchNo());
        moveInStorage.setQaCode(allocationDetail.getQaCode());
        moveInStorage.setSalesCode(allocationDetail.getSalesCode());
        moveInStorage.setSalesName(allocationDetail.getSalesName());
        moveInStorage.setRfid(allocationDetail.getRfid());
        moveInStorage.setMeter(allocationDetail.getMeter());
        moveInStorage.setShelfCode(shelfCode);
        moveInStorage.setCarCode(allocationDetail.getInCarCode());
        List<Car> lstCar = carDAO.selectByMap(new HashMap<String, Object>(){{
            put("CODE", allocationDetail.getInCarCode());
        }});
        if (lstCar.size()>0){
            moveInStorage.setIncarerid(lstCar.get(0).getLoginer());
        }
        moveInStorage.setWarehouseCode(allocationDetail.getInWarehouseCode());
        moveInStorage.setInStorageId(userId);
        moveInStorage.setInstorageTime(new Date());
        moveInStorage.setEntityNo(allocationDetail.getEntityNo());
        moveInStorage.setDishnumber(allocationDetail.getDishnumber());
        moveInStorageDAO.insert(moveInStorage);

        //更改库存库位，设置库存状态
        StorageInfo storageInfo = storageInfoDAO.selectOne(new StorageInfo(){{
            setRfid(rfid);
        }});
        storageInfo.setShelfCode(shelfCode);
        storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
        storageInfoDAO.updateById(storageInfo);

        //恢复行车状态为可用
        carDAO.updateCarByCode(allocationDetail.getInCarCode(),"", Long.valueOf(EmumConstant.carState.UNUSED.getCode()));
        //库位不可用
        shelfImpl.setShelfState(shelfCode, allocation.getFactoryCode(), allocation.getInWarehouseCode(),0);

        //临时解决方案，把原库位设为占用（因为目前使用移库的情况就是，叉车叉到场地，发现库位有线，那么就把叉车上的线做移库，所以原库位肯定是要占用状态）
        if ("1".equals(moveSoluation)){
            shelfImpl.setShelfState(allocationDetail.getOutShelfCode(),allocation.getFactoryCode(),allocation.getInWarehouseCode(),0);
        }

        return new PdaResult();
    }

    /**
     * 移库主界面扫码，移库单主界面支持直接扫码，扫码分三种情况
     *   1.检索后没有一样的质保号，那么跳入新增的提交界面，要多一个行车的选择，可选可不选
     *   2.检索后有一样的质保号，并且该质保号已经完成了移库出库，那么就直接跳入入库界面，移库入库界面行车可选可不选
     *   3.检索后有一样的质保号，但是该质保号没有完成移库出库，那么提示“未出库，请先确认出库！”
     * @param rfid rfid
     * @param barcode 二维码
     * @param barcodeType 二维码类型
     * @param userId 用户主键
     * @return PdaResult
     */
    @Override
    public PdaResult moveStorageScan(String rfid,String barcode,String barcodeType,Long userId){
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("barcode", barcode);
        queryMap.put("barcodeType", barcodeType);
        queryMap.put("rfid", rfid);
        List<AllocationDetail> allocationDetailList = pdaDAO.findAllocationDetailByqbr(queryMap);
        //没有这个移库任务，直接进入新增界面
        if(allocationDetailList==null || allocationDetailList.size()==0){
            return pdaDAO.findStorageInfoByqbr(queryMap)==null?new PdaResult(1,"库存中没有此线盘信息，请确认该线盘是否已入库","") :
                    new PdaResult(2,"", moveStorageInfoList(rfid, userId, barcode, barcodeType).data);
        }else {
            //有移库任务
            queryMap.put("stateList",Arrays.stream("1,2".split(",")).map(Long::parseLong).collect(Collectors.toList()));
            allocationDetailList = pdaDAO.findAllocationDetailByqbr(queryMap);
            //有相同质保号的移库任务，任务状态为还未出库完成，提示要先完成
            if(allocationDetailList!=null && allocationDetailList.size()>0){
                return new PdaResult(1, "此线盘在其他的移库出库任务中，请先完成！", "");
            }else{
                queryMap.put("stateList",Arrays.stream("3,4".split(",")).map(Long::parseLong).collect(Collectors.toList()));
                allocationDetailList = pdaDAO.findAllocationDetailByqbr(queryMap);
                //有相同质保号的移库任务，任务状态为还未入库完成，进入入库界面
                if(allocationDetailList!=null && allocationDetailList.size()>0){
                    AllocationDetail allocationDetail = allocationDetailList.get(0);
                    //进入移库入库界面,走一遍移库入库扫码的方法，直接传返回值就行了，moveInStorageList也是取返回值的
                    InstorageDetail instorageDetail = instorageDetailDAO.selectByMap(new HashMap<String, Object>(){{
                        put("QACODE", allocationDetail.getQaCode());
                    }}).get(0);

                    Allocation allocation = allocationDAO.selectById(allocationDetail.getPId());
                    Warehouse warehouse = warehouseDAO.selectById(allocation.getInWarehouseId());
                    String outCarCode = allocationDetail.getOutCarCode();
                    Car car = null;
                    if (StringUtils.isNotBlank(outCarCode)){
                        car = carDAO.selectList(new EntityWrapper<Car>().eq("CODE", outCarCode)).get(0);
                    }

                    List<Shelf> recommendList = shelfImpl.selectRecommentList(warehouse.getFactoryCode(), warehouse.getCode(),
                            allocationDetail.getOuterDiameter()!=null ? allocationDetail.getOuterDiameter().toString():"",
                            allocationDetail.getDrumType(), allocationDetail.getOutCarCode(), allocationDetail.getOutShelfCode(),
                            car != null? car.getWarehouseArea():"", allocationDetail.getSalesCode(), allocationDetail.getSuperWide(),
                            "黑色".equals(instorageDetail.getColour())|| StringUtils.isBlank(instorageDetail.getColour()) ? 0 : 1);
                    if(recommendList==null || recommendList.size()==0) {
                        recommendList = new ArrayList<>();
                        List<Shelf> list = shelfDAO.getRecommendShelf(warehouse.getCode(), warehouse.getFactoryCode(),
                                car != null && StringUtils.isNotBlank(car.getWarehouseArea()) ?
                                Arrays.asList(car.getWarehouseArea().split(",")) : new ArrayList<>())
                                .stream().filter(s -> !allocationDetail.getOutShelfCode().equals(s.getCode())).collect(Collectors.toList());
                        recommendList.add(list.size() > 0 ? list.get(0) : new Shelf());
                    }

                    allocationDetail.setInCarCode(outCarCode);
                    allocationDetail.setState(EmumConstant.locationChangeStatus.START_CHANGE_IN.getCode());
                    allocationDetail.setStartInStorageTime(new Date());
                    allocationDetailDAO.updateById(allocationDetail);

                    //设置行车状态为不可用
                    carDAO.updateCarByCode(outCarCode, recommendList.size()>0 ? recommendList.get(0).getCode() : "",
                            Long.valueOf(EmumConstant.carState.INSTORAGING.getCode()));

                    //记录推荐库位
                    ShipLoadingDetail shipLoadingDetail = new ShipLoadingDetail();
                    shipLoadingDetail.setCreateTime(new Date());
                    shipLoadingDetail.setMaterialCode(recommendList.size() > 0 ? recommendList.get(0).getCode() : "");
                    shipLoadingDetail.setQaCode(instorageDetail.getQaCode());
                    shipLoadingDetail.setPId(userId);
                    shipLoadingDetail.setShipNo("移库入库");
                    shipLoadingDetailDAO.insert(shipLoadingDetail);

                    Map<String, Object> map = new HashMap<>(3);
                    map.put("detail",allocationDetail);
                    map.put("warehouseIn",warehouse);
                    map.put("shelveList",recommendList);

                    return new PdaResult(3,"", map);
                }else {
                    //新增单条移库任务
                    return pdaDAO.findStorageInfoByqbr(queryMap) == null ?
                            new PdaResult(1,"库存中没有此线盘信息，请确认该线盘是否已入库","") :
                            new PdaResult(2,"", moveStorageInfoList(rfid, userId, barcode, barcodeType).data);
                }
            }
        }
    }

    /**
     * 返回指定人下的盘点任务
     * @param userId 用户主键
     * @return PdaResult 点击盘点模块进入后展示的列表
     */
    @Override
    public PdaResult inventoryPlanSelect(Long userId) {
        List<Inventory> inventories = pdaDAO.inventoryPlanSelect(userId);
        inventories.forEach(inventory ->
                inventory.setName(factoryAreaDAO.getWarehouseNames(Arrays.asList(inventory.getFactorycode().split(",")))));
        return new PdaResult(inventories);
    }

    /**
     * 盘点扫描时获取物料的详情
     * @param factorycode 厂区编码
     * @param warehouse	仓库编码
     * @param rfid rfid
     * @param barcode 扫描参数
     * @param barcodeType 扫描类型
     * @param userId 用户主键
     * @param ebsCode  EBS盘点单号
     * @return StorageInfo 库存物料
     */
    @Override
    public PdaResult getMaterialInfo(String factorycode, String warehouse, String rfid, String barcode, String barcodeType, String userId,
                                     String ebsCode) {
        //有没有对此线盘做过扫码操作
        List<Externalcable> lstExternalcable = externalcableDAO.selectList(new EntityWrapper<Externalcable>()
                .eq("2".equalsIgnoreCase(barcodeType),"ORDERDISTRIBUTE", rfid)
                .eq("0".equalsIgnoreCase(barcodeType),"QACODE", barcode)
                .eq("1".equalsIgnoreCase(barcodeType),"INSPECTNO", barcode)
                .eq("EBS_CODE", ebsCode));
        //记录盘点扫码日志,当此盘点单中已经对此线盘做过扫码操作,则提示，否则新增
        if(lstExternalcable.size()>0&&lstExternalcable.get(0).getNum()==1){
            return new PdaResult(1, "已盘点扫码，请勿重复操作！", "");
        }
        Externalcable externalcable = new Externalcable();
        //盘点是否提交：0否；1是
        externalcable.setNum(0);
        //扫码人姓名
        externalcable.setBuyorderno(userDAO.selectById(userId).getName());
        //扫描类型，0:质保号  1：批次号  2：RFID
        externalcable.setReceiptno(barcodeType);
        if ("2".equalsIgnoreCase(barcodeType)){
            externalcable.setOrderdistribute(rfid);
        }
        if ("1".equalsIgnoreCase(barcodeType)){
            externalcable.setInspectno(barcode);
        }
        if ("0".equalsIgnoreCase(barcodeType)){
            externalcable.setQacode(barcode);
        }
        //扫码人ID
        externalcable.setTransactionId(Long.valueOf(userId));
        //EBS盘点单号
        externalcable.setEbsCode(ebsCode);
        externalcableDAO.insert(externalcable);

        //在库存表中查询线盘信息
        StorageInfo storageInfo = pdaDAO.findStorageInfoByqbr(new HashMap<String, Object>(){{
            put("barcodeType", barcodeType);
            put("barcode", barcode);
            put("rfid",rfid);
        }});

        List<Split> lstSplit = splitDAO.selectList(new EntityWrapper<Split>().eq("QACODE", barcode));
        //拆分表有拆分后的盘，不能盘点（有重复质保号）
        if(lstSplit.size()>0){
            return new PdaResult(1, "改盘是有重复质保号的分段盘，请手动记录！", "");
        }
        if (storageInfo == null){
            return new PdaResult(1, "该盘未入库，请记录质保号并联系管理员！", "");
        }
        Warehouse wh = warehouseDAO.selectOne(new Warehouse(){{
            setCode(storageInfo.getWarehouseCode());
            setFactoryCode(storageInfo.getOrg());
        }});
        List<Inventory> inventories = new ArrayList<>();
        if (wh!=null){
            inventories = inventoryDAO.selectList(new EntityWrapper<Inventory>()
                    .eq("EBS_CODE", ebsCode)
                    .like("FACTORYCODE",wh.getId().toString()));
        }

        if (inventories.size() == 0){
            //判断扫描的货所在的仓库是否在此盘点单下
            return new PdaResult(1, "该线盘不属于此盘点任务！", "");
        }else{
            List<Shelf> lstShelf = shelfDAO.selectList(new EntityWrapper<Shelf>()
                    .eq("CODE", storageInfo.getShelfCode())
                    .eq("WAREHOUSECODE",storageInfo.getWarehouseCode())
                    .eq("FACTORYCODE", storageInfo.getOrg()));
            storageInfo.setShelfCode(lstShelf.size()>0?lstShelf.get(0).getCodeComplete():"");

            return new PdaResult(storageInfo);
        }
    }

    /**
     * 解析提交的盘点信息，再存入盘点明细表
     * @param queryMap 参数
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult inventoryPlanAdd(Map<String, Object> queryMap) {
        //盘点任务id
        String planId = (String) queryMap.get("inventoryId");
        //手持机登录用户id
        String userId = (String) queryMap.get("userId");
        //EBS盘点单号
        String ebsCode = inventoryDAO.selectById(planId).getEbsCode();
        //单位
        String unit = (String) queryMap.get("unit");
        //标签初始化表中扫描出来的数据
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> infoList = (List<Map<String, Object>>) queryMap.get("inventoryInfos");

        //记录盘点扫码日志,修改扫码状态为已提交盘点
        List<Externalcable> lstExternalcable = externalcableDAO.selectByMap(new HashMap<String, Object>(){{
            put("QACODE", infoList.get(0).get("qaCode"));
            put("EBS_CODE", ebsCode);
        }});
        if (lstExternalcable.size()>0){
            Externalcable externalcable = lstExternalcable.get(0);
            //盘点是否提交（0否；1是）
            externalcable.setNum(1);
            //盘点提交人ID
            externalcable.setBuyorderline(Long.valueOf(userId));
            //盘点提交人姓名
            externalcable.setMaterialcode(userDAO.selectById(userId).getName());
            externalcableDAO.updateById(externalcable);
        }

        //更新标签表盘点编辑的米数，库位
        instorageDetailDAO.updateBatches(infoList);
        /*//更新库存表盘点编辑的米数，库位
        storageInfoDAO.updateBatches(infoList);*/

        List<InventoryRegistration> lstAdd = new LinkedList<>(), lstUpdate = new LinkedList<>();
        //根据提交上来的线盘的rfid，在标签表查询基础属性
        inventoryRegistrationDAO.selectInfoInventoryStateList(infoList).forEach(instorageDetail -> {
            //instorageDetail.getInventoryShelf()是盘点库位完整版
            //盘点结果
            String result;
            //库存库位-头编码
            String shelfCode = instorageDetail.getShelfCode();
            //盘点库位-头编码
            String inventoryShelfCode = instorageDetail.getInventoryShelfCode();
            //库存米数
            String meter = instorageDetail.getMeter();
            //盘点米数
            String inventoryMeter = instorageDetail.getInventoryMeter();

            final boolean b = Double.parseDouble(meter) > Double.parseDouble(inventoryMeter);

            //库位相同
            if(shelfCode.equals(inventoryShelfCode)){
                //数量相同
                if(meter.equals(inventoryMeter)){
                    //正常
                    result = "1";
                }else{
                    //数量不同
                    //库存米数大于盘点米数
                    if(b){
                        //盘亏
                        result = "3";
                    }else {
                        //库存米数小于盘点米数
                        //盘盈
                        result = "2";
                    }
                }
            }else{
                //库位不相同
                //数量相同
                if(meter.equals(inventoryMeter)){
                    //错位正常
                    result = "4";
                }else{
                    //数量不同
                    //库存米数大于盘点米数
                    if(b){
                        //错位盘亏
                        result = "6";
                    }else {
                        //库存米数小于盘点米数
                        //错位盘盈
                        result = "5";
                    }
                }
            }

            //获取对应EBS盘点单号下的盘点明细，如果不存在就新增；存在就更新
            InventoryRegistration registration = inventoryRegistrationDAO.getRegistrationInfoByRfid(instorageDetail.getRfid(), ebsCode);
            //true不存在
            boolean existFlag = registration == null;
            registration = existFlag ? new InventoryRegistration() : registration;
            registration.setPlanId(planId);
            registration.setRfid(instorageDetail.getRfid());
            registration.setQacode(instorageDetail.getQaCode());
            registration.setShelfid(instorageDetail.getShelfCode());
            registration.setWarehousecode(instorageDetail.getWarehouseCode());
            registration.setUploadTime(new Date());
            registration.setUserCode(String.valueOf(userId));
            registration.setUserName(userDAO.selectById(userId).getUsername());
            registration.setMeter(instorageDetail.getMeter());
            registration.setMaterialcode(instorageDetail.getMaterialCode());
            registration.setResult(result);
            registration.setOrg(instorageDetail.getFactoryCode());
            registration.setEditmeter(instorageDetail.getInventoryMeter());
            registration.setEditshelf(instorageDetail.getInventoryShelf());
            //米数审核待执行
            registration.setState(3L);
            //库位审核
            registration.setShelfState(shelfCode.equals(inventoryShelfCode)?2:3);
            registration.setUnit("千米".equals(unit)?"KM":"T");
            if (existFlag) {
                lstAdd.add(registration);
            } else {
                lstUpdate.add(registration);
            }
        });

        if(lstUpdate.size()>0){
            inventoryRegistrationDAO.updateBatches(lstUpdate);
        }
        if(lstAdd.size()>0){
            inventoryRegistrationDAO.insertBatches(lstAdd);
        }

        //更新盘点计划为盘点登记中
        inventoryRegistrationDAO.updateExamStatus(Integer.parseInt(planId), Long.valueOf(EmumConstant.inventoryState.IN_AUDIT.getCode()));
        return new PdaResult();
    }
        
    /**
     * 盘点修改库位界面中获取所有的库位
     * @param code 模糊查询条件
     * @param pageNo 页码
     * @param size 每页数量
     * @return Shelf 库位
     */
    @Override
    public PdaResult getInventoryShelf(String code,int pageNo,int size) {
        return new PdaResult(pdaDAO.getallemptyshelf(new Page(pageNo, size), code));
    }

    /**
     * 拆分提交接口
     * @param queryMap 参数
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult splitSubmit(Map<String, Object> queryMap) {
        List<StorageInfo> lstStorageInfo = storageInfoDAO.selectList(new EntityWrapper<StorageInfo>().eq("RFID", queryMap.get("rfid")));
        if(lstStorageInfo==null||lstStorageInfo.size()==0){
            return new PdaResult(1, "库存中没有此线盘信息，请联系管理员查看", "");
        }
        //原库存
        StorageInfo storageInfo = lstStorageInfo.get(0);

        //在拆分表查下是否已经被分过
        List<Split> hasSplitList = splitDAO.selectList(new EntityWrapper<Split>()
                .like("QACODE", storageInfo.getQaCode())
                .orderBy("ID",false));
        String lastBatchNo = "1";
        if (hasSplitList.size()>0){
            //最后一次分的批次号
            lastBatchNo = hasSplitList.get(0).getBatchNo();
            //最后一次分的批次号_后的值+1
            lastBatchNo = String.valueOf(Integer.parseInt(lastBatchNo.substring(lastBatchNo.length() - 1))+1);
        }

        Split split = new Split();
        split.setMaterialCode(storageInfo.getMaterialCode());
        split.setBatchNo(storageInfo.getBatchNo()+"_"+lastBatchNo);
        split.setQaCode(storageInfo.getQaCode());
        //拆分的盘要入的库位
        List<Shelf> splitShelfList = shelfDAO.selectList(new EntityWrapper<Shelf>().eq("CODE_COMPLETE", queryMap.get("shelfCode")));
        if(splitShelfList.size()>0){
            Shelf splitShelf = splitShelfList.get(0);
            split.setWarehouseCode(splitShelf.getWarehouseCode());
            split.setOrg(splitShelf.getFactoryCode());
            split.setShelfCode(splitShelf.getCode());
        }
        split.setMeter((String) queryMap.get("meter"));

        //获取序列
        int seqRfid = fewmDAO.selectSeqRfid();
        String rfid = new DecimalFormat("000000000000").format(seqRfid);
        split.setRfid(rfid);
        split.setSplitTime(new Date());
        split.setSalesCode(storageInfo.getSalesCode());
        split.setSalesName(storageInfo.getSalesName());
        split.setSplitStorageId(Long.valueOf(queryMap.get("userId").toString()));
        split.setEntityNo(storageInfo.getEntityNo());
        split.setOrderno(storageInfo.getOrderno());
        split.setOrderline(storageInfo.getOrderline());
        //分出的盘具编码
        split.setDishnumber((String)queryMap.get("dishnumber"));
        split.setState(EmumConstant.storageInfoState.NORMAL.getCode());
        //修改库存米数
        storageInfo.setMeter(String.valueOf(Double.parseDouble(storageInfo.getMeter()) - Double.parseDouble((String)queryMap.get("meter"))));

        storageInfoDAO.updateById(storageInfo);

        //生成盘号：库位编码第一位字母+盘类型+盘大小+日期标识+流水号(虚拟盘除外，虚拟盘用盘具编码作为盘号)
        String drumno = "";
        if (StringUtils.isNotBlank(split.getDishnumber())){
            Dish dish = dishDAO.selectOne(new Dish() {{
                setCode(split.getDishnumber());
            }});
            //生成流水号
            List<FactoryArea> factorySerialnumList = factoryAreaDAO.selectByMap(new HashMap<String,Object>(){{
                put("CODE", split.getOrg());
            }});
            String serialnum = (factorySerialnumList !=null && factorySerialnumList.size()>0
                    && StringUtils.isNotBlank(factorySerialnumList.get(0).getSerialnum()))
                    ? factorySerialnumList.get(0).getSerialnum() : "0000";
            serialnum = String.format("%04d", Integer.parseInt(serialnum) + 1);

            //更新流水号
            if(factorySerialnumList!=null&&factorySerialnumList.size() > 0) {
                FactoryArea factoryArea = factorySerialnumList.get(0);
                factoryArea.setSerialnum(serialnum);
                factoryAreaDAO.updateById(factoryArea);
            }
            //零头库或者虚拟盘都不生成盘号
            drumno = dish == null || "1327100013".equals(dish.getCode()) || "F003".equals(split.getWarehouseCode()) ? "" :
                    split.getShelfCode().charAt(0)+ ("铁木盘".equals(dish.getDrumType()) ? Constant.STRING_ONE :
                    "全木盘".equals(dish.getDrumType()) ? Constant.STRING_TWO : Constant.STRING_THREE) +
                    new DecimalFormat("000").format(Long.parseLong(dish.getOuterDiameter() != null ?
                    dish.getOuterDiameter() : "0")/10) + DateUtils.getDays().substring(2) + serialnum ;
        }
        split.setOuterdiameter(drumno);
        splitDAO.insert(split);

        //分盘接口录入离线接口执行表
        Map<String, Object> xmlMap = new HashMap<>(8);
        //组织
        xmlMap.put("org_id", instorageDetailDAO.selectOne(new InstorageDetail(){{
            setRfid(storageInfo.getRfid());
        }}).getOrg());
        //质保号
        xmlMap.put("qacode", split.getQaCode());
        //批次号
        xmlMap.put("new_lot_number", split.getBatchNo());
        //米数
        xmlMap.put("length", split.getMeter());
        //盘具编码
        xmlMap.put("pan_code", split.getDishnumber());
        //盘号
        xmlMap.put("pan_num", drumno);
        //原批次号
        xmlMap.put("old_lot_number", storageInfo.getBatchNo());
        //库位
        xmlMap.put("shelf_code", split.getShelfCode());

        while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS030 + split.getQaCode() + "PDA")){
            try {
                TimeUnit.MILLISECONDS.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //把接口编码+质保号放到内存中
        ConRunningMap.addItem(EbsInterfaceEnum.FEWMS030 + split.getQaCode() + "PDA");
        interfaceDoServiceImpl.insertDo(EbsInterfaceEnum.FEWMS030,"EBS接口-分盘", JSONObject.toJSONString(xmlMap), DateUtils.getTime(),
                split.getQaCode(), split.getBatchNo(),null, "");
        ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS030 + split.getQaCode() + "PDA");
        return new PdaResult();
    }

    /**
     * 获取重新绑定RFID绑定表
     * @param qaCode 质保单号
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult reSetrRfidBind(String qaCode) {
        List<RfidBind> lstRfidBind;
        if ("-1".equals(qaCode)) {
            lstRfidBind = rfidBindDAO.getRfidBind(null);
        } else {
            lstRfidBind = rfidBindDAO.getRfidBind(qaCode);
            if (lstRfidBind == null || lstRfidBind.isEmpty()) {
                lstRfidBind = new ArrayList<>();
                //从装包表中查信息
                List<InstorageDetail> lstInstorageDetail = instorageDetailDAO.getRfidBind(qaCode);
                if (lstInstorageDetail != null && lstInstorageDetail.size() != 0) {
                    for (InstorageDetail detail : lstInstorageDetail) {
                        RfidBind rfidBind = new RfidBind();
                        rfidBind.setRfid(detail.getRfid());
                        rfidBind.setMaterialCode(detail.getMaterialCode());
                        rfidBind.setMaterialName(detail.getMaterialName());
                        rfidBind.setBatchNo(detail.getBatchNo());
                        rfidBind.setMeter(detail.getMeter());
                        rfidBind.setQaCode(detail.getQaCode());
                        rfidBind.setDishnumber(detail.getDishnumber());
                        rfidBind.setModel(detail.getModel());
                        rfidBind.setDrumType(detail.getDrumType());
                        rfidBind.setOuterDiameter(detail.getOuterDiameter());
                        rfidBind.setInnerDiameter(detail.getInnerDiameter());
                        lstRfidBind.add(rfidBind);
                    }
                }
            }
        }
        return new PdaResult(lstRfidBind);
    }

    /**
     * 获取拆分主表信息
     * @return PdaResult
     */
    @Override
    public PdaResult splitTypeIsZero() {
        return new PdaResult(splitInstorageDAO.getInstorageSplitType());
    }

    /**
     * 根据id查询拆分入库表信息
     * @param pid 主表id
     * @return PdaResult
     */
    @Override
    public PdaResult splitBelong(String pid) {
        return new PdaResult(splitInstorageDAO.getsplitBelong(pid));
    }

    /**
     * 返回盘信息列表
     * @param code 查询条件
     * @param pageNo 页码
     * @param pageSize 每页数量
     * @return PdaResult
     */
    @Override
    public PdaResult getDishList(String code,int pageNo,int pageSize) {
        return new PdaResult(dishDAO.selectAll(new Page(pageNo, pageSize), code));
    }

    /**
     * 根据rfid修改状态
     * @param rfid rfid
     * @return PdaResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PdaResult updateRfidType(String rfid) {
        List<RfidBind> rfidList = rfidBindDAO.selectByMap(new HashMap<String, Object>(1) {{
            put("RFID", rfid);
        }});

        if (rfidList!=null && rfidList.size()>0){
            RfidBind rfidBind = new RfidBind();
            rfidBind.setType("1");
            rfidBindDAO.update(rfidBind, new EntityWrapper<RfidBind>().eq("RFID", rfid));
        }

        return new PdaResult();
    }

    /**
     * 根据用户获取厂区
     * @param userId 用户主键
     * @return List<FactoryArea>
     */
    @Override
    public PdaResult getFactorys(String userId){
        return new PdaResult(factoryAreaDAO.selectList(new EntityWrapper<FactoryArea>()
                .in("CODE", userDAO.selectById(Long.valueOf(userId)).getFactoryCode())));
    }

    /**
     * 根据rfid获取货物详情
     * @param rfid rfid
     * @param barcode 根据扫描类型对应不同的参数
     * @param barcodeType 扫描类型，0:质保号  1：批次号  2：RFID
     * @return InstorageDetail
     */
    @Override
    public PdaResult findInfoByRfid(String rfid,String barcode,String barcodeType){
        return "0".equals(barcodeType) ? new PdaResult(pdaDAO.getMaterialInfo2(barcode,0)) : "1".equals(barcodeType) ?
                new PdaResult(pdaDAO.getMaterialInfo2(barcode,1)) : new PdaResult(pdaDAO.getMaterialInfo2(rfid,2));
    }

    /**
     * 扫描获取库存物料详情（分盘扫码也是用的这个）
     * @param rfid rfid
     * @param barcode 批次号/质保号
     * @param barcodeType 扫描类型
     * @return StorageInfo 库存物料
     */
    @Override
    public PdaResult getStorageInfoDetail(String rfid,String barcode,String barcodeType) {
        StorageInfo storageInfo = pdaDAO.getStorageInfoDetail(rfid, barcode, barcodeType);
        return storageInfo == null ? new PdaResult(1, "当前扫描的线盘不存在，请联系管理员查看！", "") : new PdaResult(storageInfo);
    }

    /**
     * 物资流转单补打界面查询
     * @param circulationNo 流转单单号
     * @param carNo 车牌号
     * @param fromFactory 出发厂
     * @param toFactory 目的厂
     * @param page 页码
     * @param size 每页数量
     * @return List<ExchangePrint>
     */
    @Override
    public PdaResult selectWzlzPrintPage(String circulationNo,String carNo,String fromFactory,String toFactory,String page,String size){
        return new PdaResult(exchangePrintDAO.findPatchPrintList(new Page(Integer.parseInt(page),Integer.parseInt(size)),
                circulationNo, carNo,fromFactory,toFactory),exchangePrintDAO.findPatchPrintCount(circulationNo, carNo,fromFactory,toFactory));
    }

    /**
     * 物资流转单补打打印
     * @param circulationNo 流转单单号
     * @return PdaResult
     */
    @Override
    public PdaResult patchPrint(String circulationNo){
        boolean issuccess = exchangePrintServiceImpl.patchPrint(circulationNo);
        return issuccess ? new PdaResult() : new PdaResult(1, "系统错误！", "");
    }

    /**
     * 获取手持机最新版本号，url地址
     * @return Map<String,Object>
     */
    @Override
    public Map<String,Object> findPdaConfig(){
        return pdaDAO.findPdaConfig();
    }
}
